Type aliases by ahejlsberg · Pull Request #957 · microsoft/TypeScript
Documenting the endpoint of the very long conversation we had today spurred by @NoelAbrahams' suggestion of not adding a new keyword. Our approach was basically to talk only about the desired semantics of type aliases, and then decide the keyword based on what the behavior of those rules were.
First, we want the following to be valid (disregard whether we use type or interface at this point):
type u = string|number|{n: string};type g = Array<number>;type t = [number, number];type s = typeof SomeClass;type p = string;type r = Date;type f = () => void;
We do not want this to be valid.
type o = { n: number; };
The reason for not wanting the last declaration is that someone might write o above, and then someone else would (quite reasonably) want to write interface S extends o { ... }. The type system restricts the types in a heritage clause to be named object types, and o would not be a named type (it is an alias for an anonymous type). It would be very annoying to have .d.ts authors or other people writing type o = { body }; when they should have written interface o { body; }. Same goes for re-opening the type o - we would not want to disallow this simply because of the syntax it was written in.
The proposal we ended up with is that a type alias is only a valid declaration if it it takes one of the forms listed above (or an equivalent parenthesization thereof). We briefly discussed making type o = { body } a synonym for interface o { body }, but rejected this as we do not want two ways of doing the exact same thing.
Other basic things to note:
- Type aliases may not be 'reopened' the way interfaces can
- You may
extendorimplementa type alias only if its referent is a named object type (gorrabove) - Error messages will show the resolved type of a type alias
- .d.ts generation will preserve type aliases if they are written explicitly in a type annotation (but not if they are the result of an inference)