繁体   English   中英

基于字符串文字类型参数的变量返回类型

[英]Variable return types based on string literal type argument

我可以根据 TypeScript 1.8 或 2.0 中字符串文字类型参数的值设置变量返回类型吗?

type Fruit = "apple" | "orange" 
function doSomething(foo : Fruit) : string | string[] {
    if (foo == "apple") return "hello";
    else return ["hello","world"];
}

var test : string[] = doSomething("orange");

错误:TS2322:输入“字符串” string[]' 不能分配给类型 'string[]'。

是的,您可以使用重载签名来实现您想要的:

type Fruit = "apple" | "orange"

function doSomething(foo: "apple"): string;
function doSomething(foo: "orange"): string[];
function doSomething(foo: Fruit): string | string[]
{
    if (foo == "apple") return "hello";
    else return ["hello", "world"];
}

let orange: string[] = doSomething("orange");
let apple: string = doSomething("apple");

尝试将doSomething("apple")分配给orange会产生编译时类型错误:

let orange: string[] = doSomething("apple");
 // ^^^^^^
 // type 'string' is not assignable to type 'string[]'

TypeScript Playground 上的现场演示

需要注意的是,确定使用哪个重载签名必须始终在函数实现中手动完成,并且函数实现必须支持所有重载签名

TypeScript 中的每个重载没有单独的实现,例如在 C# 中。 因此,我发现在运行时加强 TypeScript 类型检查是一个很好的做法,例如:

switch (foo) {
    case "apple":
        return "hello";
    case "orange":
        return ["hello", "world"];
    default:
        throw new TypeError("Invalid string value.");
}

我有一个更好的方法。 使用泛型然后用作参数的类型(这样你就不需要手动传递泛型,typescript 会自动推断它)。 然后您可以使用该类型并选择正确的返回类型。

type Fruit = 'apple' | 'orange';
function doSomething<P extends Fruit>(foo: P): ({ apple: string; orange: string[] })[P] {
  if (foo === 'apple') return 'hello';
  return ['hello','world];
}
const x: string = doSomething('apple');
const y: string[] = doSomething('orange');

通过这种方式,您可以根据自动传递的参数更改函数的返回类型。

是的,你可以。 您只需要使用instanceof测试您的test变量。 然后打字稿将限制类型。

type Fruit = "apple" | "orange" 
function doSomething(foo: Fruit): string | string[] {
    if (foo == "apple") return "hello";
    else return ["hello","world"]
}

// here the type is still inferred as: string | string[]
var test = doSomething("orange");

if (test instanceof String) {
    // TypeScript knows test is type: string
    doSomethingWithString(test);
} else {
    // TypeScript knows test is type: string[]
    doSomethingWithStringArray(test);
}

function doSomethingWithString(input: string) {}
function doSomethingWithStringArray(input: string[]) {}

更新

您可能只想使该方法通用。

function doSomething<T>(foo: Fruit): T {
    if (foo == "apple") return "hello";
    else return ["hello","world"]
}

var test1 = doSomething<string>("apple");
var test2 = doSomething<string[]>("orange");

或者另一种选择是将流程反转为这样的:

type Fruit = "apple" | "orange" 
function doSomething(foo: Fruit): void {
    if (foo == "apple") 
        doSomthingWithString("hello");
    else 
        doSomethingWithStringArray(["hello","world"]);
}

function doSomethingWithString(input: string) {}
function doSomethingWithStringArray(input: string[]) {}

更新

实际上,我相信John White的答案要好得多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM