TypeScript keyof 索引类型太宽 [英] TypeScript keyof index type is too wide

查看:18
本文介绍了TypeScript keyof 索引类型太宽的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

抱歉,我确定这已经在某处得到了回答,但我不知道该去谷歌搜索什么.如果标题中的术语有误,请编辑我的问题.

Apologies, I'm sure this has been answered somewhere, but I'm not sure what to google. Please do edit my question if the terms in the title are wrong.

我有这样的事情:

type RowData = Record<string, unknown> & {id: string}; 


type Column<T extends RowData, K extends keyof T> = {  
  key: K; 
  action: (value: T[K], rowData: T) => void;
}

type RowsAndColumns<T extends RowData> = {
  rows: Array<T>; 
  columns: Array<Column<T, keyof T>>; 
}

并且 TypeScript 应该能够通过检查行的形状以及为列赋予的 key 值来推断 action 函数的类型:

And TypeScript should be able to infer the types of the action functions, by examining the shape of the rows, and what key value has been given to the column:

即:

function myFn<T extends RowData>(config: RowsAndColumns<T>) {

}

myFn({
  rows: [
    {id: "foo", 
      bar: "bar", 
      bing: "bing", 
      bong: {
        a: 99, 
        b: "aaa"
      }
    }
  ], 
  columns: [
    {
      key: "bar", 
      action: (value, rowData) => {
          console.log(value);
      }
    },
     {
      key: "bong", 
      action: (value, rowData) => {
          console.log(value.a); //Property 'a' does not exist on type 'string | { a: number; b: string; }'.

      }
    }
  ]
}); 

游乐场链接

问题是,TypeScript 似乎将值的类型 (value: T[K]) 推导为T 的 all 键可访问的所有类型' 而不是仅使用列对象中提供的键.

The problem is, TypeScript seems to be deriving the type of value (value: T[K]) as 'the types of all accessible by all keys of T' rather than using just the key provided in the column object.

为什么 TypeScript 会这样做,我该如何解决?

Why is TypeScript doing this, and how can I solve it?

最好的答案是定义一些特定的术语和概念.

What would make some good answer is defining some specific terms and concepts.

我想我想将我的 K extends keyof T 更改为类似K 是 T 的键,但只有一个键,并且它永远不会改变".

I imagine I want to change my K extends keyof T to be something like 'K is a keyof T, but only one key, and it never changes'.

推荐答案

如果您希望 T 的键是 union文字"bong";|冰"|...(而不仅仅是 string),那么你可以表达一个类型,它本身就是 Column<的 union/code> 用于 keyof T 中的每个键 K.

If you expect the keys of T to be a union of literals like "bong" | "bing" | ... (and not just string), then you can express a type which is itself the union of Column<T, K> for each key K in keyof T.

我通常通过立即执行此操作 索引(查找)映射输入:

I usually do this via immediately indexing (lookup) into a mapped type:

type SomeColumn<T extends RowData> = {
  [K in keyof T]-?: Column<T, K>
}[keyof T]

但你也可以通过分布式条件类型来实现:

type SomeColumn<T extends RowData> = keyof T extends infer K ?
  K extends keyof T ? Column<T, K> : never : never;

无论哪种方式,您的 RowsAndColumns 类型都将使用 SomeColumn 而不是 Column:

Either way, your RowsAndColumns type would then use SomeColumn instead of Column:

type RowsAndColumns<T extends RowData> = {
  rows: Array<T>;
  columns: Array<SomeColumn<T>>;
}

这使您想要的用例按预期工作而不会出现编译错误:

And this makes your desired use case work as expected without compile errors:

myFn({
  rows: [
    {
      id: "foo",
      bar: "bar",
      bing: "bing",
      bong: {
        a: 99,
        b: "aaa"
      }
    }
  ],
  columns: [
    {
      key: "bar",
      action: (value, rowData) => {
        console.log(value);
      }
    },
    {
      key: "bong",
      action: (value, rowData) => {
        console.log(value.a);
      }
    },
  ]
});

代码的游乐场链接

这篇关于TypeScript keyof 索引类型太宽的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆