Skip to main content

基础语法

以下是TypeScript的基础语法汇总,涵盖了类型注解、接口、类、函数、泛型等核心概念:

1. 类型注解

TypeScript通过类型注解为变量、函数参数和返回值添加静态类型:

// 基本类型
let num: number = 42;
let str: string = "hello";
let isDone: boolean = false;
let notSure: any = "maybe a string";

// 数组
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b"];

// 元组(固定长度和类型的数组)
let person: [string, number] = ["Alice", 30];

// 枚举
enum Color { Red = 1, Green = 2, Blue = 4 }
let c: Color = Color.Green;

// void 不返回值的函数的返回值
type VoidFunction = () => void;

// object 表示非原始值(即不是 number、string、boolean、null、undefined、symbol 或 bigint 的值)
let obj: object;

obj = {}; // 合法:普通对象
obj = [1, 2, 3]; // 合法:数组
obj = () => {}; // 合法:函数
obj = new Date(); // 合法:类实例

// 错误:不能赋值原始类型
obj = 123; // 错误
obj = "hello"; // 错误
obj = null; // 错误(除非启用 "strictNullChecks": false)


// unknown 表示任何值,必须先判断类型才能使用
function f1(a: any) {
a.b(); // OK
}
function f2(a: unknown) {
a.b();
// 'a' is of type 'unknown'.
}

// never 函数没有返回值
function fail(msg: string): never {
throw new Error(msg);
}

// Function
// 全局类型 Function 描述了 JavaScript 中所有函数值上存在的属性,如 bind、call、apply 和其他属性。它还具有始终可以调用 Function 类型的值的特殊属性;这些调用返回 any
function doSomething(f: Function) {
return f(1, 2, 3);
}

// Rest 参数
// Inferred as 2-length tuple
const args = [8, 5] as const;
const angle = Math.atan2(...args);

2. 接口(Interfaces)

接口定义对象的结构,用于类型检查:

interface Person {
name: string;
age?: number; // 可选属性
readonly id: number; // 只读属性
greet?(msg: string): void; // 可选方法
}

const user: Person = {
name: "Bob",
id: 123,
greet: (msg) => console.log(`${msg}, ${this.name}`)
};

索引访问类型

type Age = Person["age"];   // number

type I1 = Person["age" | "name"]; // number | string

type I2 = Person[keyof Person]; // number | string | (msg: string): void

使用 number 获取数组元素的类型(可以和typeof配合)

 const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];

type Person = typeof MyArray[number]; // type Person = { name: string; age: number;}

index 索引签名,索引签名属性只允许使用某些类型:string、number、symbol、模板字符串模式和仅包含这些类型的联合类型。

interface StringArray {
[index: number]: string; // 此处index为形参,可以任意命名
}

const myArray: StringArray = getStringArray();
const secondItem = myArray[1];

interface NumberOrStringDictionary {
[index: string]: number | string; // index会约束length 和name的类型定义
length: number; // ok, length is a number
name: string; // ok, name is a string
}

extends 接口继承

interface Colorful {
color: string;
}

interface Circle {
radius: number;
}

interface ColorfulCircle extends Colorful, Circle {}

const cc: ColorfulCircle = {
color: "red",
radius: 42,
};

&交集

interface Colorful {
color: string;
}
interface Circle {
radius: number;
}

type ColorfulCircle = Colorful & Circle;

泛型接口

interface Box<Type> {
contents: Type;
}

interface Apple {
// ....
}

// Same as '{ contents: Apple }'.
type AppleBox = Box<Apple>;

function setContents<Type>(box: Box<Type>, newContents: Type) {
box.contents = newContents;
}

3. 类(Classes)

支持面向对象编程,包括继承、访问修饰符等:

class Point {
// 设置初始值
x = 0;

// 只读属性
readonly name: string = "world";

// 公共成员
public greet() {
console.log("hi!");
}

// protected 成员仅对声明它们的类的子类可见。实例化后是不可见的
protected getName() {
return "hi";
}

// 不允许访问成员,即使从子类也是
private x = 0;

// 静态成员
// 前面可添加public、protected 和 private
// 静态成员也会被继承
static x = 0;

// 特殊静态名称: name、length 和 call属性名无法定义为静态成员
static name = "S!"; // 会报错
}

// private 允许在类型检查期间使用括号表示法进行访问(ts为软私有)
const point = new Point();
console.log(point.x) // 报错, Property 'x' is private and only accessible within class 'Point'.
console.log(point['x']) // 不报错

// JavaScript 的私有字段 (#)为硬私有,不能使用括号表示法进行访问
class Dog {
#barkAmount = 0;
personality = "happy";

constructor() {}
}

class Animal {
protected name: string; // 受保护属性,子类可访问
constructor(name: string) {
this.name = name;
}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m.`);
}
}

// 继承extends
class Dog extends Animal {
private breed: string; // 私有属性,仅类内部可访问
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
bark() {
console.log("Woof!");
}
}

const dog = new Dog("Buddy", "Labrador");
dog.move(10); // 输出: Buddy moved 10m.
dog.bark(); // 输出: Woof!

// 实现implements
interface Pingable {
ping(): void;
}
// 如果类未能正确实现它,则会发出错误
class Sonar implements Pingable {
ping() {
console.log("ping!");
}
}

// 实现多接口
interface Loggable {
log(message: string): void;
}

interface Serializable {
toJSON(): string;
}

class Logger implements Loggable, Serializable {
log(message: string) {
console.log(message);
}

toJSON() {
return JSON.stringify({ type: "Logger" });
}
}


// 泛型类
class Box<Type> {
// 泛型类的 static 成员永远不能引用类的类型参数
static defaultValue: Type; // 会报错

contents: Type;
constructor(value: Type) {
this.contents = value;
}
}


// 基于this的类型守卫
class FileSystemObject {
isFile(): this is FileRep {
return this instanceof FileRep;
}
isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked(): this is Networked & this {
return this.networked;
}
constructor(public path: string, private networked: boolean) {}
}

class FileRep extends FileSystemObject {
constructor(path: string, public content: string) {
super(path, false);
}
}

class Directory extends FileSystemObject {
children: FileSystemObject[];
}

interface Networked {
host: string;
}

const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");

if (fso.isFile()) {
fso.content; // const fso: FileRep
} else if (fso.isDirectory()) {
fso.children; // const fso: Directory
} else if (fso.isNetworked()) {
fso.host; // const fso: Networked & FileSystemObject
}


// 参数属性:用于将构造函数参数转换为具有相同名称和值的类属性
class Params {
constructor(
public readonly x: number,
protected y: number,
private z: number
) {
// No body necessary
}
}
const a = new Params(1, 2, 3);
console.log(a.x);

(property) Params.x: number
console.log(a.z); // 报错,Property 'z' is private and only accessible within class 'Params'.


// 类表达式,类表达式不需要名称
const someClass = class<Type> {
content: Type;
constructor(value: Type) {
this.content = value;
}
};

const m = new someClass("Hello, world");


// InstanceType 构造函数签名,获取实例化后的类型
class Point {
createdAt: number;
x: number;
y: number
constructor(x: number, y: number) {
this.createdAt = Date.now()
this.x = x;
this.y = y;
}
}
type PointInstance = InstanceType<typeof Point>

function moveRight(point: PointInstance) {
point.x += 5;
}

const point = new Point(3, 4);
moveRight(point);
point.x; // => 8


// abstract类和成员
// 抽象类不能直接实例化
// 抽象方法或抽象字段必须存在于抽象类中
// 如果忘记实现基类的抽象成员,我们将收到一个错误
abstract class Base {
abstract getName(): string;

printName() {
console.log("Hello, " + this.getName());
}
}

// 类结构相同,则两个类的类型相等
// 类之间也存在子类型关系
class Person {
name: string;
age: number;
}

class Employee {
name: string;
age: number;
salary: number;
}

// OK
const p: Person = new Employee();

4. 函数(Functions)

支持类型注解和可选参数:

// 函数类型定义
function add(a: number, b: number): number {
return a + b;
}

// 可选参数(必须放在最后)
function greet(name: string, msg?: string): string {
return msg ? `${msg}, ${name}` : `Hello, ${name}`;
}

// 箭头函数
const multiply = (a: number, b: number): number => a * b;

// 函数调用签名
type DescribableFunction = {
description: string; // 属性签名
(someArg: number): boolean; // 调用签名
};
function doSomething(fn: DescribableFunction) {
console.log(fn.description + " returned " + fn(6));
}

function myFunc(someArg: number) {
return someArg > 3;
}
myFunc.description = "default description";

doSomething(myFunc);


// 构造签名
type SomeConstructor = {
new (s: string): SomeObject;
};
function fn(ctor: SomeConstructor) {
return new ctor("hello");
}

// 泛型函数
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}


// 函数重载
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3);

5. 泛型(Generics)

创建可复用的组件,支持多种类型:

// 泛型函数
function identity<T>(arg: T): T {
return arg;
}

// 字面量声明函数
let myIdentity: <Type>(arg: Type) => Type = identity;
// 对象字面量类型的调用签名
let myIdentity: { <Type>(arg: Type): Type } = identity;

let output1 = identity<string>("myString"); // 指定类型
let output2 = identity(100); // 类型推断

// 泛型类
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}

范型约束

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");

范型类型为构造函数

// 以下两种声名方式效果一样
// c: { new (): Type } 函数的对象类型声明
// c: new () => A es6箭头函数语法的扩展,此处c只是描述一个构造函数的类型,并非特指箭头函数,和箭头函数不能被new调用并不冲突

// 简单示例
function create<Type>(c: { new (): Type }): Type {
return new c();
}

// 高级示例
class BeeKeeper {
hasMask: boolean = true;
}

class ZooKeeper {
nametag: string = "Mikle";
}

class Animal {
numLegs: number = 4;
}

class Bee extends Animal {
numLegs = 6;
keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}

createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;

范型默认值

declare function create<T extends HTMLElement = HTMLDivElement, U extends HTMLElement[] = T[]>(
element?: T,
children?: U
): Container<T, U>;

方差注释

// 协方差(协变): Producer<T> -> Producer<U> 的关系与  T -> U 的关系方向相同
// 逆方差(逆变): Consumer<T> -> Consumer<U> 的关系与 U -> T 的关系相同(方向反转)
// in 逆变
interface Consumer<in T> {
consume: (arg: T) => void;
}
// out 协变
interface Producer<out T> {
make(): T;
}
// in out 不变
interface ProducerConsumer<in out T> {
consume: (arg: T) => void;
make(): T;
}

使用限制:

  • in T(逆变):T 只能出现在输入位置(如参数)。
  • out T(协变):T 只能出现在输出位置(如返回值)。
  • in out T(不变):T 可同时出现在输入和输出位置,但类型必须严格相等。

6. 联合类型(Union Types)

允许变量具有多种类型之一:

let value: string | number;
value = "hello"; // 合法
value = 100; // 合法
// value = true; // 错误:不是 string 或 number

7. 类型别名(Type Aliases)

为类型创建自定义名称:

type Point = {
x: number;
y: number;
};

type ID = string | number;

function printCoord(pt: Point) {
console.log(`(${pt.x}, ${pt.y})`);
}

8. 交叉类型(Intersection Types)

组合多个类型为一个类型:

type Admin = { role: string };
type User = { name: string };
type AdminUser = Admin & User; // 同时拥有 role 和 name

const adminUser: AdminUser = {
role: "admin",
name: "Alice"
};

9. 类型操作

typeof

在运行时检查类型:

function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // 类型缩小为 string
} else {
console.log(value.toFixed(2)); // 类型缩小为 number
}
}

in运算符

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
if ("swim" in animal) {
return animal.swim();
}

return animal.fly();
}

is类型谓词

function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}

!非 null 断言

function getArea(shape: Shape) {
if (shape.kind === "circle") {
return Math.PI * shape.radius! ** 2;
}
}

never穷举性检查

type Shape = Circle | Square;

function getArea(shape: Shape) {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.sideLength ** 2;
default:
const _exhaustiveCheck: never = shape;
return _exhaustiveCheck;
}
}

extends 类型约束

function longest<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {
return a;
} else {
return b;
}
}

// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);
// Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.

条件类型

interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}

type Example1 = Dog extends Animal ? number : string; // number


// 条件类型约束
type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;

interface Email {
message: string;
}

interface Dog {
bark(): void;
}

type EmailMessageContents = MessageOf<Email>; // type EmailMessageContents = string

type DogMessageContents = MessageOf<Dog>; // type DogMessageContents = never

分布式条件类型

type ToArray<Type> = Type extends any ? Type[] : never;

// 分布在string | number
type StrArrOrNumArr = ToArray<string | number>; // type StrArrOrNumArr = string[] | number[]

// 若不想被分布,可以用方括号将 extends 关键字的每一侧括起来
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

// 'ArrOfStrOrNum' is no longer a union.
type ArrOfStrOrNum = ToArrayNonDist<string | number>; // type ArrOfStrOrNum = (string | number)[]

类型映射

映射类型建立在索引签名的语法之上,通常通过 keyof 创建来迭代键以创建类型

type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};

type CreateMutable<Type> = {
readonly [Property in keyof Type]: Type[Property];
};

as 子句类型重映射

// Remove the 'kind' property
type RemoveKindField<Type> = {
[Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};

interface Circle {
kind: "circle";
radius: number;
}

type KindlessCircle = RemoveKindField<Circle>; // type KindlessCircle = { radius: number;}

模板文本类型

// 联合类型会交叉相乘
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// type AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"


// 根据类型内部的信息定义新字符串
const person = makeWatchedObject({
firstName: "Saoirse",
lastName: "Ronan",
age: 26,
});

// makeWatchedObject has added `on` to the anonymous Object

person.on("firstNameChanged", (newValue) => {
console.log(`firstName was changed to ${newValue}!`);
});

//
type PropEventSource<Type> = {
on<Key extends string & keyof Type>
(eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void): void;
};

/// Create a "watched object" with an `on` method
/// so that you can watch for changes to properties.
declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;



// 内置字符串操作类型:
// Uppercase<StringType> 转大写
type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting> // type ShoutyGreeting = "HELLO, WORLD"

// Lowercase<StringType> 转小写

// Capitalize<StringType> 首字母转大写
type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>; // type Greeting = "Hello, world"

// Uncapitalize<StringType> 首字母转小写

10. 枚举(Enums)

为一组数值或字符串赋予友好名称:

// 数字枚举(默认从0开始)
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}

// 字符串枚举
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}

// 枚举与数字兼容,数字与枚举兼容。来自不同枚举类型的枚举值被视为不兼容
enum Status {
Ready,
Waiting,
}
enum Color {
Red,
Blue,
Green,
}
let status = Status.Ready;
status = Color.Green; // Error

11. 装饰器(Decorators)

用于类和类成员的元编程:

// 类装饰器示例
function logClass(constructor: Function) {
console.log(`Class ${constructor.name} was created`);
}

@logClass
class MyClass {
// ...
}

12. 命名空间(Namespaces)

组织代码的方式,避免全局命名冲突:

namespace Validation {
export interface Validator {
isValid(value: any): boolean;
}
export class EmailValidator implements Validator {
isValid(email: string) {
return email.includes("@");
}
}
}

const validator: Validation.Validator = new Validation.EmailValidator();

13. 类型断言(Type Assertion)

手动指定变量类型:

let value: any = "hello";
let length: number = (value as string).length; // 或 <string>value

14. 可选链(Optional Chaining)

安全访问可能不存在的属性:

const user = {
name: "Alice",
address: {
street: "123 Main St"
}
};

const street = user.address?.street; // 如果 address 不存在,返回 undefined

15. 空值合并(Nullish Coalescing)

仅当左侧值为 nullundefined 时使用右侧默认值:

const count = null ?? 100; // 结果:100
const name = "" ?? "Default"; // 结果:""(空字符串不为 null/undefined)

16.类型运算符keyof

type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish; // A = number

type A = number

type Mapish = { [k: string]: boolean };
type M = keyof Mapish; // M = number | string, JavaScript 对象键总是被强制转换为字符串

17.类型推断infer

使用限制:

  1. 只能在条件类型中使用
    infer 必须出现在 extends 子句中,例如:

    // 正确
    type A<T> = T extends infer U ? U : never;

    // 错误:不能直接使用infer
    type B<T> = infer U; // 报错
  2. 推断变量必须在条件类型的true分支中使用

    // 正确
    type C<T> = T extends infer U ? U : never;

    // 错误:infer U未被使用
    type D<T> = T extends infer U ? never : never; // 无意义
  3. 多条件推断中的类型合并
    infer 出现在联合类型中时,会生成所有可能的推断结果的联合:

    type UnionReturnType<T> = T extends () => infer R ? R : never;

    type Result = UnionReturnType<(() => number) | (() => string)>; // 结果:number | string

提取函数返回类型

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 使用示例
type Num = ReturnType<() => number>; // 结果:number
type Str = ReturnType<(x: string) => string>; // 结果:string
  • 解释
    infer R 捕获函数的返回类型,若 T 是函数类型,则返回 R,否则返回 never

提取数组元素类型

type ElementType<T> = T extends (infer U)[] ? U : T;

// 使用示例
type Num = ElementType<number[]>; // 结果:number
type Str = ElementType<string[]>; // 结果:string
type NotArray = ElementType<boolean>; // 结果:boolean
  • 解释
    T 是数组类型,则 infer U 捕获其元素类型;否则返回 T 本身。

提取Promise的resolved类型

type ResolvedType<T> = T extends Promise<infer U> ? U : T;

// 使用示例
type Num = ResolvedType<Promise<number>>; // 结果:number
type Str = ResolvedType<Promise<string>>; // 结果:string
type NotPromise = ResolvedType<boolean>; // 结果:boolean
  • 解释
    T 是Promise类型,则 infer U 捕获其内部的resolved类型;否则返回 T

提取函数参数类型

type Parameters<T> = T extends (...args: infer P) => any ? P : never;

// 使用示例
type Args = Parameters<(a: number, b: string) => void>; // 结果:[number, string]
  • 解释
    infer P 捕获函数的参数类型,返回一个元组类型。

提取构造函数的实例类型

type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never;

// 使用示例
class MyClass { constructor() {} }
type MyClassInstance = InstanceType<typeof MyClass>; // 结果:MyClass
  • 解释
    infer R 捕获构造函数的返回类型(即实例类型)。

条件类型链中的多重推断

type DeepReturnType<T> = 
T extends () => infer U ?
U extends () => any ? DeepReturnType<U> : U :
T;

// 使用示例
type NestedFn = () => () => () => number;
type Result = DeepReturnType<NestedFn>; // 结果:number
  • 解释
    递归推断嵌套函数的最终返回类型。

与泛型结合

type GetReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never;

// 使用示例
function add(a: number, b: number): number {
return a + b;
}

type AddResult = GetReturnType<typeof add>; // 结果:number

与映射类型结合

type PromiseValues<T> = {
[K in keyof T]: T[K] extends Promise<infer U> ? U : T[K];
};

// 使用示例
type Obj = {
a: Promise<number>;
b: string;
};

type Result = PromiseValues<Obj>; // 结果:{ a: number; b: string; }

18.模块

// 只能导入类型的 import 语句:
import type { Cat, Dog } from "./animal.js";

// 单个导入类型,以 type 为前缀
import { createCatName, type Cat, type Dog } from "./animal.js";