Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable return types based on string literal type argument

Tags:

Can I have variable return type based on the value of a string literal type argument in TypeScript 1.8 or 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[]'.

like image 908
daniel.sedlacek Avatar asked Sep 26 '16 10:09

daniel.sedlacek


People also ask

What are string literal types?

The string literal type allows you to specify a set of possible string values for a variable, only those string values can be assigned to a variable. TypeScript throws a compile-time error if one tries to assign a value to the variable that isn't defined by the string literal type.

What are the two types of string literals?

A string literal with the prefix L is a wide string literal. A string literal without the prefix L is an ordinary or narrow string literal. The type of narrow string literal is array of char .

How many types of string literals are there?

There are three sets of literal types available in TypeScript today: strings, numbers, and booleans; by using literal types you can allow an exact value which a string, number, or boolean must have.

What is a type literal?

Literal types let you indicate that an expression is equal to some specific primitive value. For example, if we annotate a variable with type Literal["foo"] , mypy will understand that variable is not only of type str , but is also equal to specifically the string "foo" .


Video Answer


1 Answers

Yes, you can use overload signatures to achieve exactly what you want:

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

Trying to assign doSomething("apple") to orange would yield a compile-time type-error:

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

Live demo on TypeScript Playground

It is important to note that determining which overload signature was used must always be done in the function implementation manually, and the function implementation must support all overload signatures.

There are no separate implementations per overload in TypeScript as there are in, say, C#. As such, I find it a good practice to reinforce TypeScript type-checks at runtime, for example:

switch (foo) {     case "apple":         return "hello";     case "orange":         return ["hello", "world"];     default:         throw new TypeError("Invalid string value."); } 
like image 194
John Weisz Avatar answered Oct 07 '22 01:10

John Weisz