2016-09-26 43 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

相關問題