TypeScript 类型定义总结
总结 TypeScript 中常见的类型定义模式以供快速参考。
内置原始类型
string
:文本数据,例如hello
number
:所有数字,包括整数和浮点数,例如100
、3.14
bigint
:任意大的整数,例如12345678901234567890n
boolean
:真值或假值,例如true
、false
symbol
:唯一且不可变的值,例如Symbol('key')
undefined
:声明但未赋值的变量,例如undefined
null
:故意不赋值,例如null
void
:用作不返回值的函数的返回类型,例如function log(): void { console.log('Hello'); }
never
:表示永远不会发生的值,例如function fail(message: string): never { throw new Error(message); }
unknown
:表示任意值,但比any
更安全,使用前必须进行类型检查,例如let value: unknown = 1;
any
:禁用类型检查,例如let a: any = 'hello'; a = 1;
对象类型
- Plain Object (
object
)
let person: object = { name: 'Alice', age: 30 };
- Specific Object Shapes (via
{}
)
let user: { name: string; age: number } = { name: 'Bob', age: 25 };
- Interfaces
interface User {
name: string;
age: number;
}
let u: User = { name: 'Carol', age: 22 };
- Enums
enum Color {
Red,
Green,
Blue,
}
- Type Aliases
type Point = { x: number; y: number };
- Arrays (
Array<T>
orT[]
)
let scores: number[] = [90, 85, 100];
let names: Array<string> = ['Alice', 'Bob'];
- Tuples
let point: [number, number] = [10, 20];
let userInfo: [string, number] = ['Alice', 30];
- Classes
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
const dog = new Animal('Doggo');
- Functions (
Function
type)
let greet: (name: string) => string = (name) => `Hello, ${name}!`;
- Callable Objects
interface Callable {
(x: number): number;
description: string;
}
const square: Callable = Object.assign((x: number) => x * x, { description: 'Squares a number' });
- Constructors (
new
)
interface Constructor {
new (s: string): object;
}
- Index Signatures
interface StringMap {
[key: string]: string;
}
let dict: StringMap = { key1: 'value1', key2: 'value2' };
- Indexed Access Types
// Accessing Object Properties
interface Person {
name: string;
age: number;
}
type PersonName = Person['name']; // `PersonName` is `string`
type PersonAge = Person['age']; // `PersonAge` is `number`
// Accessing Array Elements
type Numbers = number[];
type FirstNumber = Numbers[0]; // `FirstNumber` is `number`
// Using With String Literal Types
type Colors = 'red' | 'green' | 'blue';
type ColorLength = Colors['length']; // `ColorLength` is `number`
// Accessing Nested Object Properties
interface Car {
brand: string;
specs: {
engine: string;
wheels: number;
};
}
type EngineType = Car['specs']['engine']; // `EngineType` is `string`
type WheelCount = Car['specs']['wheels']; // `WheelCount` is `number`
// Conditional Types with Indexed Access
type PropertyType<T, K extends keyof T> = T[K];
interface Car {
brand: string;
year: number;
}
type CarBrand = PropertyType<Car, 'brand'>; // `CarBrand` is `string`
type CarYear = PropertyType<Car, 'year'>; // `CarYear` is `number`
- Mapped Types
type ReadOnly<T> = {
readonly [K in keyof T]: T[K];
};
- Template Literal Types
type Greeting = `Hello ${string}`;
let greeting: Greeting = 'Hello world'; // Works fine
greeting = 'Hello John'; // Works fine
greeting = 'Hi John'; // Error: Type 'Hi John' is not assignable to type 'Greeting'
- Utility Types
Partial<T>
Required<T>
Readonly<T>
Pick<T, K>
Omit<T, K>
Record<K, T>
Exclude<T, U>
Extract<T, U>
NonNullable<T>
ReturnType<T>
Parameters<T>
Awaited<T>
// ...
- Intersection Types
type Worker = User & { jobTitle: string };
- Union Types
type Shape = Circle | Rectangle;
interface Circle {
radius: number;
}
interface Rectangle {
width: number;
height: number;
}
- Structural Typing (Duck Typing)
let obj: {name: string} = {name: 'Alice', age: 30}; // allowed!
- Literal Object Types
type Status = {
state: 'loading' | 'success' | 'error';
};
-
Special Types
object
:仅限非原始类型(不能为null
或undefined
)。{}
:几乎任何非空/未定义的值(甚至42
也是{}
!)。Object
:JavaScript 的Object
类型:几乎任何值(甚至函数、数组)。
-
Special:
Record<string, unknown>
pattern
type LooseObject = Record<string, unknown>;
// equivalent to
type LooseObject = {
[key: string]: unknown;
};
接口详细
- Basic Interface
interface User {
name: string;
age: number;
}
const user: User = { name: 'Alice', age: 30 };
- Optional Properties
interface User {
name: string;
age?: number; // optional
}
const user1: User = { name: 'Alice' };
const user2: User = { name: 'Bob', age: 25 };
- Readonly Properties
interface User {
readonly name: string;
age: number;
}
const user: User = { name: 'Alice', age: 30 };
user.name = 'Bob'; // Error: Cannot assign to 'name' because it is a read-only property.
- Function Types in Interfaces
interface Greet {
(name: string): string;
}
const greet: Greet = (name) => `Hello, ${name}`;
- Extending Interfaces
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
const employee: Employee = { name: 'Alice', employeeId: 123 };
- Interface with Index Signatures
interface Dictionary {
[key: string]: string;
}
const myDict: Dictionary = {
apple: 'A fruit',
car: 'A vehicle'
};
- Intersection with Other Types
interface Product {
name: string;
price: number;
}
type DiscountedProduct = Product & {
discount: number;
};
const discounted: DiscountedProduct = { name: 'Shoes', price: 50, discount: 10 };
- Interfaces with Classes
interface Movable {
move(): void;
}
class Car implements Movable {
move() {
console.log('The car is moving!');
}
}
- Interface with Method Signatures
interface Calculator {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
}
const myCalculator: Calculator = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
- Interfaces with Optional Method Signatures
interface Logger {
log?: (message: string) => void;
}
const logger: Logger = {
log: (message) => console.log(message)
};
const silentLogger: Logger = {}; // This is valid because `log` is optional
- Interfaces with
extends
and Multiple Inheritance
interface Worker {
work(): void;
}
interface Manager {
manage(): void;
}
interface Supervisor extends Worker, Manager {}
const supervisor: Supervisor = {
work() {
console.log('Working');
},
manage() {
console.log('Managing');
}
};
- Merging Interfaces
interface Person {
name: string;
}
interface Person {
age: number;
}
const person: Person = { name: 'Alice', age: 30 };
- Interface with Type Parameters (Generics)
interface Box<T> {
value: T;
}
const stringBox: Box<string> = { value: 'Hello' };
const numberBox: Box<number> = { value: 42 };
- Hybrid Types
interface Counter {
(start: number): string; // Function signature
value: number; // Property
}
const counter: Counter = (start: number) => `Count: ${start}`;
counter.value = 0;
类型详细
- Basic Type Aliases
type Name = string;
const userName: Name = 'Alice'; // Equivalent to 'string' but using the alias.
- Union Types
type Status = 'loading' | 'success' | 'error';
const currentStatus: Status = 'loading'; // Valid
- Intersection Types
type Person = {
name: string;
age: number;
};
type Employee = Person & {
employeeId: number;
};
const employee: Employee = { name: 'Alice', age: 30, employeeId: 123 };
- Literal Types
type Color = 'red' | 'green' | 'blue';
const color: Color = 'green'; // Valid
- Tuple Types
type Point = [number, number];
const point: Point = [10, 20]; // Valid
- Function Types
type Greet = (name: string) => string;
const greet: Greet = (name) => `Hello, ${name}`;
- Optional Properties
type User = {
name: string;
age?: number; // Optional property
};
const user1: User = { name: 'Alice' };
const user2: User = { name: 'Bob', age: 30 };
- Readonly Properties
type User = {
readonly name: string;
age: number;
};
const user: User = { name: 'Alice', age: 30 };
user.name = 'Bob'; // Error: Cannot assign to 'name' because it is a read-only property.
- Mapped Types
type Person = { name: string; age: number };
type ReadOnlyPerson = { readonly [K in keyof Person]: Person[K] };
const person: ReadOnlyPerson = { name: 'Alice', age: 30 };
person.name = 'Bob'; // Error: Cannot assign to 'name' because it is a read-only property.
- Conditional Types
type IsString<T> = T extends string ? 'Yes' : 'No';
type A = IsString<string>; // 'Yes'
type B = IsString<number>; // 'No'
- Type Inference
type User = { name: string; age: number };
const user = { name: 'Alice', age: 30 }; // TypeScript infers `User` type automatically
- Type Aliases with Generics
type Box<T> = { value: T };
const stringBox: Box<string> = { value: 'Hello' };
const numberBox: Box<number> = { value: 42 };
- Union of Object Types
type Success = { status: 'success'; data: string };
type Error = { status: 'error'; message: string };
type Response = Success | Error;
const response: Response = { status: 'success', data: 'Hello, world!' };
- Intersection of Object Types
type Person = { name: string };
type Employee = { employeeId: number };
type Worker = Person & Employee;
const worker: Worker = { name: 'Alice', employeeId: 123 };
- Type Guards and Type Aliases
type User = { name: string; age: number };
type Admin = { name: string; role: string };
function isUser(user: User | Admin): user is User {
return (user as User).age !== undefined;
}
const person: User | Admin = { name: "Alice", age: 30 };
if (isUser(person)) {
console.log(person.age); // Safe, because it's narrowed to 'User'
}
- Utility Types Using
type
type User = { name: string; age: number };
// Partial<User> makes all properties optional
type PartialUser = Partial<User>;
// Pick<User, 'name'> picks specific properties
type UserName = Pick<User, 'name'>;
在“接口”和“类型”之间选择
- 使用
interface
来定义对象形状、类以及需要可扩展性的情况(例如,当您想要合并接口或扩展它们时)。 - 对于更复杂的类型(例如并集、交集、泛型)以及非对象类型(例如数组、元组、函数或更高级的场景)的别名,请使用
type
。
keyof
和 typeof
的比较
keyof
: returns a union of property names (keys) of an object type
type Person = {
name: string;
age: number;
};
type PersonKeys = keyof Person; // "name" | "age"
typeof
: returns the type of a value (likestring
,number
, or any object type)
const userName = 'Alice';
type UserNameType = typeof userName; // string
function greet(user: string) {
return `Hello, ${user}`;
}
type GreetFunctionType = typeof greet; // (user: string) => string
keyof
andtypeof
used together
const person = {
name: 'Alice',
age: 30,
};
type PersonKeys = keyof typeof person; // "name" | "age"
什么在“值”空间和“类型”空间中都存在
- Variables and Constants
const userName = 'Alice'; // `userName` is a **value** in value space and has the value `"Alice"`
type UserNameType = typeof userName; // `typeof userName` is a **type** in type space (`string`)
const userAge = 30; // `userAge` is a **value** in value space
type UserAgeType = typeof userAge; // `typeof userAge` is a **type** in type space (`number`)
- Functions
function greet(name: string): string {
return `Hello, ${name}!`;
}
const greetType: typeof greet = greet; // `greet` is a **value** in value space and has the function implementation.
type GreetType = typeof greet; // `typeof greet` is a **type** in type space that describes the function's signature
- Classes
class Person {
constructor(public name: string, public age: number) {}
}
const person1 = new Person('Alice', 30); // `person1` is a **value** in value space (an instance of `Person`)
type PersonType = typeof Person; // `typeof Person` is a **type** in type space, representing the class constructor
type PersonInstanceType = Person; // `Person` is also a **type** in type space, representing the type of instances created by the class
- Enums
enum Status {
Loading = 'loading',
Success = 'success',
Error = 'error'
}
const currentStatus = Status.Loading; // `currentStatus` is a **value** in value space (the string "loading")
type StatusType = typeof Status; // `typeof Status` is a **type** in type space (the enum itself)
type StatusValues = Status; // `Status` is a **type** in type space, representing the enum values
- Type Assertions
const someValue: any = 'Hello!';
const stringValue = someValue as string; // `stringValue` is a **value** in value space, and we assert that it has a **type** `string` in type space
不可擦除类型
typeof
Operator
const str = 'Hello';
type StrType = typeof str; // 'string' is the type inferred.
// In runtime, `typeof str` will be a reference to the actual value (string "Hello").
- Enums
enum Color {
Red,
Green,
Blue
}
const colorValue = Color.Red; // Color is a non-erasable value, it gets converted into an object.
after compilation:
var Color;
(function (Color) {
Color[Color['Red'] = 0] = 'Red';
Color[Color['Green'] = 1] = 'Green';
Color[Color['Blue'] = 2] = 'Blue';
})(Color || (Color = {}));
const
Assertions
const fruit = 'apple' as const; // "apple" is a literal type, this type is non-erasable.
type FruitType = typeof fruit; // "apple" is a non-erasable type because it will be part of the generated JS.
- Classes and Class Instances
class Person {
constructor(public name: string, public age: number) {}
}
const person1 = new Person('Alice', 30);
-
Interfaces (used for code generation)
接口在生成的 JavaScript 中在运行时被删除,但当用于代码生成时,它们是不可删除的类型,因为它们确保在编译时强制执行类型检查并影响生成的代码的结构。
interface IShape {
x: number;
y: number;
}
类型断言
- Angle Bracket (
<Type>
) Syntax (old syntax)
let value: unknown = 'hello';
let strLength: number = (<string>value).length;
as
Syntax (recommended, more modern syntax)
let value: unknown = 'hello';
let strLength: number = (value as string).length;
- Non-null Assertion (
!
)
let someValue: string | null = 'Hello';
// TypeScript will give an error because `someValue` could be `null`.
let length = someValue.length; // Error: Object is possibly 'null'.
// Using non-null assertion to tell TypeScript we're sure it's not null.
let length = someValue!.length; // Works fine, assuming `someValue` is never null.
- Definite Assignment Assertion (
!
)
class MyClass {
name!: string; // Use `!` to tell TypeScript this will be assigned before use.
constructor() {
// Initialization later
this.name = 'John Doe';
}
printName() {
console.log(this.name); // Works fine, name is assigned before use.
}
}
const myClassInstance = new MyClass();
myClassInstance.printName(); // Output: John Doe
- Const Assertion
let point = { x: 10, y: 20 } as const;
- Double Assertion
let someNumber: number = '123' as unknown as number;
类型谓词
function isString(value: any): value is string {
return typeof value === 'string';
}
类型断言和类型谓词的比较
- 类型断言:“我比 TypeScript 更了解——就假设它是正确的类型。”
- 类型谓词:“我会进行适当的检查,TypeScript 可以信任我的结果。”
// type assertion
let data: any = 'hello';
let length: number = (data as string).length; // Tell TS: treat 'data' as string
// type predicate
function isString(value: any): value is string {
return typeof value === 'string';
}
function example(value: any) {
if (isString(value)) {
console.log(value.toUpperCase()); // TS knows it's string safely here
}
}