无法在TypeScript中创建带有可选参数的动态类型

问题描述 投票:0回答:2

[尝试正确获取以下TypeScript类型表达式以使其具有本地尝试编写一个名为getValue(string, defValue?)的类型智能函数,如果找不到该密钥,则该函数将返回字符串或默认值。该函数的类型应为string | typeof defaultValue,lookupValue()函数应具有正确的类型来支持此功能。

至此,已经尝试了该方法的4种不同的变体,其中三种在编译或使用中均失败,最后一种情况不能完全处理类型输入,但可以编译。

//  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");

}

目标是要有满足此要求的东西:

    const big = getvalue("testBig");        // Should be type of string | undefined
    const bigDef = getvalue("testBig", "something");        // Should be type string
typescript
2个回答
1
投票
Typescript目前在可选参数和泛型方面有局限性。如果您添加了一个与泛型混合使用的可选参数,则编译器将始终采用<generic> | undefined。例如:

function doSomething<A>(param1?: A) { return param1; }

在这种情况下,param1为“ A |未定义”。这会破坏所有类型的流程,因为通用方面不包括未定义方面,而是坚持使用了它-即使在您不带参数调用doSomething()的情况下也是如此。因此,doSomething(“ jello”)的结果为string | undefined;这很愚蠢,因为人们会认为这将是字符串。 doSomething()的返回类型为{} | undefined而不只是undefined也是这种情况。

您有时可以通过用大隐喻的锤子用力敲打打字稿来解决此问题。通常,锤子包括制定正确的类型定义,然后投射所有抱怨的内容。没有一个适合所有人的尺码,但您可以这样做:

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;

首先,将R和A设置为字符串,并且默认情况下未定义。这样一来,如果编译器没有其他可用信息,则假定R / A是字符串/未定义。然后,必须设置defvalue: A以阻止编译器添加| undefined。没有| undefined,编译器可以进行代数输入。然后,您必须指定函数的结果为R | A,因为这基本上就是您想要的。下一步是告诉编译器停止基于对lookupValue的调用结果来推断“ A”是什么,因为它将错误地进行推断。这也是为什么我们需要使用“ R”而不是string | A的原因。本质上,如果您不区分lookupValue的结果(或使用字符串| 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;

我能想到的所有情况下都可以正常工作

// 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");


0
投票
您可以实现类似这样的动态可选参数:
© www.soinside.com 2019 - 2024. All rights reserved.