深入对象语法
描述对象的属性
使用接口描述对象
type Person = {
name: string
}
// 或者
interface Person {
name: string
}
Person 的子集为
type Children =
| { name: string, age: string }
| { name: string, age: number }
| { name: string, age: boolean }
| { name: string, age: null }
| { name: string, age: undefined }
| { name: string, age: object }
| { name: string, gender: string }
| { name: string, gender: number }
// 以下省略一万行
索引签名(Index Signature)
type Hash = {
[k: string]: unknown
length: number
}
type List = {
[k: number]: unknown
length: number
}
映射类型(Mapped Type)
type Hash = {
[k in string]: unknown
}
type List = {
[k in number]: unknown
}
映射类型多用于泛型
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
需要注意的是,如果使用了映射类型,对象中就不能再有其他属性了,这点与索引签名有所不同
type Hash = {
[k in string]: unknown
length: number
// ^-- A mapped type may not declare properties or methods.
}
可选属性
可选属性的含义是该属性可以不存在
interface InputProps {
defaultValue?: string;
value?: boolean;
onChange?: () => void;
}
value?: boolean 可近似的理解成 value: boolean | undefined,但是在声明对象属性时,value? 可以不写,而 value 必须写
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性
interface User {
readonly id: number;
readonly name: string;
readonly scores: number[];
age?: number;
}
const u: User = {
id: 1,
name: 'ClariS',
scores: [87, 65],
};
使用 readonly 定义的属性初始化后不能被重新赋值
u.id = 2; // ^-- Cannot assign to 'id' because it is a read-only property.ts u.scores = [100, 65] // ^-- Cannot assign to 'scores' because it is a read-only property.ts
但是并没有对 scores 内部的属性做只读约束(只读约束只在第一层)
u.scores[0] = 100; // 不报错
深入函数语法
对象的语法全都适用于函数
type F = {
(a: number, b: number): number;
readonly count?: number[];
};
const fn: F = (x, y) => x + y;
fn.count[0] = 1;
声明函数的四种方式
先写类型再赋值
type F1 = (a: number, b: number) => number; const f1: F1 = (a, b) => a + b;
箭头函数
const f2 = (a: number, b: number): number => {
return a + b;
};
type F2 = typeof f2;
普通函数
function f3(this: unknown, a: number, b: number): number {
return a + b;
}
type F3 = typeof f3;
匿名普通函数
const f4 = function (this: unknown, a: number, b: number): number {
return a + b;
};
type F4 = typeof f4;
构造函数
const f5 = new Function('a', 'b', 'return a + b');
type F5 = typeof f5;
几乎没人会这么写吧 (思考)
类型谓词
之前在联合类型中讲过,可以使用类型谓词 is 来收窄类型,当时只简单提了一下不推荐使用箭头函数,这里说一下为什么
type Person = { name: string }
type Animal = {}
function isPerson(x: Person | Animal): x is Person {
return 'name' in x
}
function fn(a: Person | Animal) {
if (isPerson(a)) {
a // Person
}
}
可以使用箭头函数实现 isPerson
const isPerson = (x: Person | Animal): x is Person => 'name' in x
但需要注意的是,如果使用的是箭头函数,不能先写类型再赋值
type A = (x: Person | Animal) => x is Person const isPerson: A = x => 'name' in x // ^--- Type '(x: Person | Animal) => boolean' is not assignable to type 'A'
在右边加上 x is Person 就不报错了
type A = (x: Person | Animal) => x is Person const isPerson: A = (x): x is Person => 'name' in x
参数相关语法
可选参数
function addEventListener(eventType: string, fn: unknown, useCapture?: boolean) {
if (useCapture === undefined) {
useCapture = false
}
// 浏览器实现
console.log(eventType, fn, useCapture)
}
addEventListener('click', () => 1)
参数默认值
function addEventListener(eventType: string, fn: unknown, useCapture = false) {
// 浏览器实现
console.log(eventType, fn, useCapture)
}
addEventListener('click', () => 1)
参数也可以是函数
function addEventListener(
eventType: string,
fn: (this: HTMLElement, e: Event) => void,
useCapture = false
) {
// 浏览器实现,这里只提供伪代码
const element = {} as HTMLElement;
const event = {} as Event;
fn.call(element, event);
console.log(eventType, fn, useCapture);
}
addEventListener('click', () => 1);
返回值也可以是函数
const add = (a: number, b: number) => a + b type CreateAdd = (x: number) => (y: number) => number const createAdd: CreateAdd = a => b => a + b add(6, 14) createAdd(6)(14)
评论区
评论加载中...