请问typescript如何给泛型的参数指定默认值?

例如

const arrToObj = <T extends Record<L | V, unknown>, L extends string, V extends string>(arr: T[], label:L = 'label' , value:V = 'value'): Record<string, T[L]>

提示如下错误

不能将类型“string”分配给类型“L”。
"string" 可赋给 "L" 类型的约束,但可以使用约束 "string" 的其他子类型实例化 "L"。ts(2322)
请问typescript如何给泛型的参数指定默认值?


回答:

string 类型其实是个类型集合.
在 TS 中,有一种类型是使用一个具体的字符串来表示的,也就是字面量类型(Literal Types).
比如 type A = 'a' ,这里 A 就表示是一个字符串为 'a' 的类型,而不能是别的字符串.
这样的字符串有无数个,对应的这样的字面量类型有无数个,而 string 就是这些所有字符串字面量类型的集合.
当指定 L extends string 时,L 有可能是 label ,也有可能不是,一切都是未知的.
这里会报错断原因,就是因为 L 需要在使用时去指定或者推断出来的,并不一定是 lable ,所以不能在不知道 L 具体的类型时就去指定它实际的值.

除了字符串字面量类型,每个基础类型都有对应的字面量类型,详细可以点击后面的参考链接,去阅读文档.

如果只是想要消除报错的话,可以直接用 as 断言成对应的类型.如下:

const arrToObj = <

T extends Record<L | V, unknown>,

L extends string,

V extends string,

>(

arr: T[],

label: L = 'label' as L,

value: V = 'value' as V,

): Record<string, T[L]> => {

return arr as any

}

不过这样会有一个问题,就是当使用默认值是,返回值里的 T[L] 不会被正确推断出来.

这个函数其实可以分为三种情况来看

  1. 没有默认值,传入三个参数
  2. value 有默认值,传入两个参数
  3. label 和 value 有默认值,传入一个参数

这时候使用函数重载来实现最合适了.在使用时也能正确推断出 T[L] 类型了.如下:

function arrToObj<

T extends Record<L | V, unknown>,

L extends string,

V extends string,

>(arr: T[], label: L, value: V): Record<string, T[L]>

function arrToObj<T extends Record<L | 'value', unknown>, L extends string>(

arr: T[],

label: L,

): Record<string, T[L | 'value']>

function arrToObj<T extends Record<'label' | 'value', unknown>>(

arr: T[],

): Record<string, T['label' | 'value']>

function arrToObj(

arr: Record<string, unknown>[],

label = 'label',

value = 'value',

) {

return arr as any

}

TS Playground


  • Function Overloads
  • Literal Types

以上是 请问typescript如何给泛型的参数指定默认值? 的全部内容, 来源链接: utcz.com/p/935911.html

回到顶部