Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TypeScript use "Like" types?

Why does TypeScript have a type and then a "like type"? An example of this is Promise<T> and PromiseLike<T>.

What are the differences between these two types? When should I use them? In this case why not just have one Promise type?

like image 503
Stewart Avatar asked May 01 '17 00:05

Stewart


People also ask

What is type {} TypeScript?

TypeScript has another type called empty type denoted by {} , which is quite similar to the object type. The empty type {} describes an object that has no property on its own.

Why does TypeScript have types and interfaces?

It uses the “interface” keyword for declaring an interface that can contain the methods, properties, and events to describe data shapes. The typescript type supports only the data types and not the use of an object. The typescript interface supports the use of the object.

Why you should not use TypeScript?

One thing that many beginners do not understand about TypeScript is that it does not guarantee type-correctness at runtime. Your TypeScript code might be fully typed and the compiler ensures you that everything must be correct… but at runtime you still get errors because your variables might be of the wrong types!

Is TypeScript structural typing?

TypeScript is a Structural Type System. A structural type system means that when comparing types, TypeScript only takes into account the members on the type. This is in contrast to nominal type systems, where you could create two types but could not assign them to each other.


1 Answers

If you look at the definition files (let's take lib.es6.d.ts) then it's pretty straight forward.

For example the ArrayLike interface:

interface ArrayLike<T> {     readonly length: number;     readonly [n: number]: T; } 

is more limited than the Array one:

interface Array<T> {     length: number;     toString(): string;     toLocaleString(): string;     push(...items: T[]): number;     pop(): T | undefined;     concat(...items: T[][]): T[];     concat(...items: (T | T[])[]): T[];     join(separator?: string): string;     reverse(): T[];     shift(): T | undefined;     slice(start?: number, end?: number): T[];     sort(compareFn?: (a: T, b: T) => number): this;     splice(start: number, deleteCount?: number): T[];     splice(start: number, deleteCount: number, ...items: T[]): T[];     unshift(...items: T[]): number;     indexOf(searchElement: T, fromIndex?: number): number;     lastIndexOf(searchElement: T, fromIndex?: number): number;          // lots of other methods such as every, forEach, map, etc      [n: number]: T; } 

It's good to have the two separated because I might want to have a function like this:

function getSize(arr: Array<any>): number {     return arr.length; }  console.log(getSize([1, 2, 3])); // works 

But it won't work with this:

function fn() {     console.log(getSize(arguments)); // error } 

It results with this error:

Argument of type 'IArguments' is not assignable to parameter of type 'any[]'.
Property 'push' is missing in type 'IArguments'.

But both will work if I do this:

function getSize(arr: ArrayLike<any>): number {     return arr.length; } 

(more on ArrayLike in MDN)

The same with Promise and PromiseLike, if I'm building a library which isn't opinionated about the implementation of the Promise then instead of doing this:

function doSomething(promise: Promise<any>) { ... } 

I'll do this:

function doSomething(promise: PromiseLike<any>) { ... } 

Then even if the user of my library is using a different implementation (bluebird) it will work just fine.

If you'll notice the definition of Promise is this:

declare var Promise: PromiseConstructor; 

Which makes it very specific, other implementations might have different properties, for example a different prototype:

interface PromiseConstructor {     readonly prototype: Promise<any>;      ... } 

I guess that the main reason that we have PromiseLike is that several implementations were available before the native one was supported (such as bluebird, Promises/A+, jQuery, and more).
In order for typescript to work with code bases that are using those implementations there must be a type other than Promise, otherwise there would be a lot of contradictions.

like image 124
Nitzan Tomer Avatar answered Oct 08 '22 11:10

Nitzan Tomer