无法使用TypeScript中的可选参数创建动态类型
正在尝试使以下TypeScript类型表达式正确以具有本地 尝试编写名为无法使用TypeScript中的可选参数创建动态类型,typescript,Typescript,正在尝试使以下TypeScript类型表达式正确以具有本地 尝试编写名为getValue(string,defValue?的类型智能函数,如果找不到键,则返回字符串或默认值。函数的类型应为string | typeof defaultValuelookupValue()函数的类型正确,可以支持这一点 在这一点上,我们尝试了该方法的4种不同变体,其中3种在编译或使用中失败,最后一种情况没有完全处理类型输入,但编译了 // This function is good -- correctly ha
getValue(string,defValue?
的类型智能函数,如果找不到键,则返回字符串或默认值。函数的类型应为string | typeof defaultValue
lookupValue()函数的类型正确,可以支持这一点
在这一点上,我们尝试了该方法的4种不同变体,其中3种在编译或使用中失败,最后一种情况没有完全处理类型输入,但编译了
// This function is good -- correctly handling the types
lookupValue<D>(record: string[], key: string, defvalue: D): D | string {
const index = this.columnHeaders[key];
const v = index !== undefined ? record[index] : undefined;
return v === undefined || v === "" ? defvalue : v.trim();
}
someFunction(record: string[]) {
// -- Test 1
const getValue = <T>(key: keyof typeof COLUMNS, defvalue = undefined) => lookupValue(record, key, defvalue);
// Argument of type '""' is not assignable to parameter of type 'undefined'.
const bigDef = getvalue("testBig", "something");
// -- Test 2
// Type 'undefined' is not assignable to type 'T'.
const getValue = <T>(key: keyof typeof COLUMNS, defvalue: T = undefined) => lookupValue(record, key, defvalue);
// -- Test 3
// Won't compile since the defvalue is "T | undefined" which isn't valid
const getValue = <T>(key: keyof typeof COLUMNS, defvalue?: T) => lookupValue(record, key, defvalue);
// -- Test 4
// Compiles but is wrong since the following getValue "works"
const getValue = <T = undefined>(key: keyof typeof COLUMNS, defvalue?: T) => lookupValue(record, key, defvalue as T);
// Works - but shouldn't
const foo: string = getValue("test");
}
Typescript目前在可选参数和泛型方面有局限性。如果添加与泛型混合的可选参数,编译器始终假定
|未定义
。例如:
function doSomething<A>(param1?: A) {
return param1;
}
首先,将R和A设置为字符串,默认情况下为未定义。因此,如果R/A没有其他信息可供处理,则编译器会假定R/A为string/undefined。然后必须设置defvalue:A
,以阻止编译器添加|未定义的
。如果没有| undefined
,编译器可以执行类型代数。然后必须指定函数的结果是R | A
,因为这基本上就是您想要的。下一步是告诉编译器停止根据调用lookupValue的结果推断“A”是什么,因为它将错误地推断。这也是为什么我们需要使用“R”而不仅仅是string | A
。本质上,如果您没有对lookupValue的结果进行大小写(或使用string | A作为结果类型),编译器会非常聪明地发现没有足够的类型信息,因此“A”要么是“未定义”要么是“字符串”,这取决于您将结果插入的内容,要么是未编译的(如果您省略了强制转换)或者,如果getValue
的返回类型设置为string | A
,则如下所示失败:
const result: string = getValue("testBig");
“A”将推断字符串是错误的,因为它应该是编译错误“无法将字符串|未定义分配给字符串”。另一种情况:
const result: string = getValue("testBig");
A
将推断为undefined
,这意味着const result
将属于string | undefined
类型,这也是错误的
为了避免上述情况,我们在第二行添加as unknown)as R | A
,以获得:
const getValue = <R = string, A = undefined>(key: string, defvalue: A = (undefined as unknown) as A): R | A =>
(lookupValue(record, key, defvalue) as unknown) as R | A;
您可以动态实现如下可选参数:
function doSomething<T extends keyof TypeDataSchema>(
type: T,
...[data]: TypeDataSchema[T] extends never ? [] : [TypeDataSchema[T]]
) {
}
interface TypeDataSchema {
'hello': number
'bye': never
}
doSomething('bye') // ok
doSomething('bye', 25) // expected 1 argument but got 2
doSomething('hello', 5) // ok
doSomething('hello') // expected 2 argument but got 1
函数doSomething(
类型:T,
…[data]:TypeDataSchema[T]从不扩展?[]:[TypeDataSchema[T]]
) {
}
接口类型数据模式{
“你好”:电话号码
“再见”:永远不会
}
doSomething('bye')//好的
doSomething('bye',25)//应为1个参数,但得到2个
doSomething('hello',5)//好的
doSomething('hello')//应为2个参数,但得到1个
谁是列
?还有T
如何与列
相关?理想情况下,我们希望列类型和T
之间存在关系,否则这比任何
都好。列是具有附加数据的对象。例如,{name:xxx,address:yyy}。所以键是“name”|“address”“--对于这个例子来说并不重要
const getValue = <R = string, A = undefined>(key: string, defvalue: A = (undefined as unknown) as A): R | A =>
(lookupValue(record, key, defvalue) as unknown) as R | A;
// ss is number | string
const ss = getValue("testBig", 1);
// bigDef is string
const bigDef = getValue("testBig", "something");
// sdf is string | undefined
const sdf = getValue("testBig", undefined);
const sdf = getValue("testBig");
// Compile error -> string | undefined can't be assigned to string
const asdfa: string = getValue("testBig");
function doSomething<T extends keyof TypeDataSchema>(
type: T,
...[data]: TypeDataSchema[T] extends never ? [] : [TypeDataSchema[T]]
) {
}
interface TypeDataSchema {
'hello': number
'bye': never
}
doSomething('bye') // ok
doSomething('bye', 25) // expected 1 argument but got 2
doSomething('hello', 5) // ok
doSomething('hello') // expected 2 argument but got 1