- The key distinction is that a type cannot be re-opened to add new properties vs an interface which is
always extendable. But this problem can be solved using intersection with type.
interface Animal {
name: string
}
interface Bear extends Animal {
honey: boolean
}
// extending type using intersection
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
- A type cannot be changed after being created.
type Window = {
title: string
}
type Window = {
ts: TypeScriptAPI
} // Error: Duplicate identifier 'Window'.
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}
const src = 'const a = "Hello World"';
window.ts.transpileModule(src, {});
- Interfaces may only be used to declare the shapes of objects, not rename primitives.
// Using type we can create custom names
// for existing primitives:
type SanitizedString = string
type EvenNumber = number
// This isn't feasible with interfaces
interface X extends string {
}
-
Interface names will always appear in their original form in error messages, but only when they are used by name.
-
Type aliases may not participate in declaration merging, but interfaces can.
-
Tuples can only be typed via the type keyword
type row = [colOne: number, colTwo: string];
- With interfaces, the subtypes have to exactly match the types declared in the super type, otherwise TS will throw an error like the one above.
interface NumLogger {
log: (val: number) => void;
}
type StrAndNumLogger = NumLogger & {
log: (val: string) => void;
}
const logger: StrAndNumLogger = {
log: (val: string | number) => console.log(val)
}
logger.log(1)
logger.log('hi')
// Typescript is totally happy. What about if I tried to extend that with interface
interface StrAndNumLogger extends NumLogger {
log: (val: string) => void;
};
// gives error Interface 'StrAndNumLogger' incorrectly extends interface 'NumLogger'
- Use the type to capture the type of an object when the type is unknown.
const orange = { color: "Orange", vitamin: "C"}
type Fruit = typeof orange
let apple: Fruit
- Use the type for creating the aliases for long or complicated types
type Primitive = number | string | boolean | null | undefined
- Use interface when you want to take advantage of declaration merging.
- Use interface for all object types where using type is not required
- Use type When trying to overload functions in object types
- Use types, to declare NonNullable type thanks to a conditional mechanism.
type NonNullable<T> = T extends null | undefined ? never : T;
- Note that an interface and type alias are not mutually exclusive. An interface can extend a type alias, and vice versa. however that a class and interface are considered static blueprints. Therefore, they can not implement / extend a type alias that names a union type.
// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x = 1;
y = 2;
}