Item 13: Know the Differences Between type and interface
May 10, 2024 ยท View on GitHub
Things to Remember
- Understand the differences and similarities between
typeandinterface. - Know how to write the same types using either syntax.
- Be aware of declaration merging for
interfaceand type inlining fortype. - For projects without an established style, prefer
interfacetotypefor object types.
Code Samples
type TState = {
name: string;
capital: string;
};
interface IState {
name: string;
capital: string;
}
const wyoming: TState = {
name: 'Wyoming',
capital: 'Cheyenne',
population: 578_000
// ~~~~~~~ Object literal may only specify known properties,
// and 'population' does not exist in type 'TState'
};
type TDict = { [key: string]: string };
interface IDict {
[key: string]: string;
}
type TFn = (x: number) => string;
interface IFn {
(x: number): string;
}
type TFnAlt = {
(x: number): string;
};
const toStrT: TFn = x => '' + x; // OK
const toStrI: IFn = x => '' + x; // OK
const toStrTAlt: TFnAlt = x => '' + x; // OK
type TBox<T> = {
value: T;
};
interface IBox<T> {
value: T;
}
interface IStateWithPop extends TState {
population: number;
}
type TStateWithPop = IState & { population: number; };
class StateT implements TState {
name: string = '';
capital: string = '';
}
class StateI implements IState {
name: string = '';
capital: string = '';
}
type AorB = 'a' | 'b';
type Input = { /* ... */ };
type Output = { /* ... */ };
interface VariableMap {
[name: string]: Input | Output;
}
type NamedVariable = (Input | Output) & { name: string };
interface Person {
name: string;
age: string;
}
type TPerson = Person & { age: number; }; // no error, unusable type
interface IPerson extends Person {
// ~~~~~~~ Interface 'IPerson' incorrectly extends interface 'Person'.
// Types of property 'age' are incompatible.
// Type 'number' is not assignable to type 'string'.
age: number;
}
type Pair = [a: number, b: number];
type StringList = string[];
type NamedNums = [string, ...number[]];
interface IState {
name: string;
capital: string;
}
interface IState {
population: number;
}
const wyoming: IState = {
name: 'Wyoming',
capital: 'Cheyenne',
population: 578_000
}; // OK
// lib.es5.d.ts
interface Array<T> {
/** Gets or sets the length of the array. */
length: number;
// ...
[n: number]: T;
}
// lib.es2015.core.d.ts
interface Array<T> {
/** Returns the index of the first element in the array where predicate... */
findIndex(
predicate: (value: T, index: number, obj: T[]) => unknown,
thisArg?: any
): number;
// ... also find, fill, copyWithin
}
export function getHummer() {
type Hummingbird = { name: string; weightGrams: number; };
const ruby: Hummingbird = { name: 'Ruby-throated', weightGrams: 3.4 };
return ruby;
};
const rubyThroat = getHummer();
// ^? const rubyThroat: Hummingbird
// get-hummer.d.ts
export declare function getHummer(): {
name: string;
weightGrams: number;
};
export function getHummer() {
// ~~~~~~~~~
// Return type of exported function has or is using private name 'Hummingbird'.
interface Hummingbird { name: string; weightGrams: number; };
const bee: Hummingbird = { name: 'Bee Hummingbird', weightGrams: 2.3 };
return bee;
};