2016-09-26 84 views
7

基于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"); 

Error: TS2322: Type 'string | string[]' is not assignable to type 'string[]'.

+3

'test'变量类型应该是'字符串[] | string' –

+1

@AlekseyL。我不同意。如果将''orange''作为参数传递给'doSomething',则总是产生一个'string []',那么'test'也具有这种类型是正确的。您需要使用[overloading](http://stackoverflow.com/a/39743710/2788872)。 –

+0

@JohnWhite'doSomething'签名清楚地表明返回类型是'string [] | string',这不是重载的情况,您只需根据特定输入 –

回答

3

当然可以。你只需要用instanceof来测试你的test变量。 Typescript将限制类型。

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[]) {} 

UPDATE

或许你只是想使通用的方法来代替。

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[]) {} 

UPDATE

其实我相信约翰·怀特的是一个更好的答案。

+0

通用将在我的情况。其他选择对于我的用例来说太麻烦了。谢谢 –

+2

其实我相信@ john-white的回答对你的具体问题是一个更好的答案。请将他的答案标记为正确答案。 – Martin

10

是的,你可以使用重载签名来达到你想要什么:

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"]; 
} 

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

Live demo on TypeScript Playground

尝试指派doSomething("apple")test1会产生一个编译时类型错误。

需要注意的是,确定使用哪个重载签名必须始终在函数实现中手动完成,并且函数实现必须为support all overload signatures

在TypeScript中每个重载都没有单独的实现,就像C#中那样。因此,这将是一个好主意,检查每个支持的类型明确,是这样的:

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

这是真的,如果这是真的,但除非我误认为不是。 Typescript支持具有不同数量参数的签名的重载方法,但不支持具有不同类型的相同数字参数的签名。字符串文字类型在编译为JS时只是字符串,所以如何区分你的三个'doSomething()'函数? – drewmoore

+0

@drewmoore *“你的三个doSomething()函数怎么能被区分?” - 在这种情况下,显然是用值检查。如果'foo'没有任何支持的值,那么在这里抛出一个'TypeError'也是个好主意。 –

+0

演示中有编译器错误:)这些值检查只能在运行时完成,而不是编译时 - 这是在执行TS类型安全时的情况 – drewmoore