一. 如何定义对象的类型
- 方式1.最基础的方式
type Person = {
name: string;
}; // 要注意这种定义的Person类型范围很大,包含 {name: string, age: 18} 等只要有{name: string}的类型。
interface Person {
name: string;
}
- 方式2. 索引签名
type Hash = {
[k: string]: unknown;
length: number;
};
// k 表示key可以用其它任意字母或者单词替代,第一个冒号后面描述key的类型,第二个冒号后面为value的类型
// 还可以写其它的类型,比如length表示所有下标的个数
type List = {
[k: number]: unknown;
length: number;
};
- 方式3. 映射类型,这种方式和方式2的主要区别,1. 不能加其它属性比如length 2. 主要用于范型
type Hash = {
[k in string]: unknown;
};
type List = {
[k in number]: unknown;
};
二. 其它一些对象的语法
-
- 问号表示可选
interface InputProps {
defaultValue?: string;
value?: string;
onChange?: () => void;
}
const props: InputProps = {}; // 什么都不写也不会报错
-
- readonly语法
interface User {
readonly id: number;
readonly name: string;
readonly scores: number[];
age?: number;
}
const u: User = {
id: 1,
name: 'Jack',
scores: [98, 99],
};
u.id = 2; // 会报错,不能改id
s.scores = [100, 100]; // 会报错
u.scores[0] = 100; // 通过下标改这样不会报错,说明readonly只管道scores这一层,不保证里面的属性不可更改
u.scores[1] = 100;
三. 深入函数语法
-
- 对象的语法全都适用于函数
type F = {
(a: number, b: number): number;
count: number;
};
// 也可以用interface,完全一样,type和interface之前的文章已经详细描述过
interface F2 {
(a: number, b: number): number;
readonly count?: number;
}
const f: F = (x, y) => {
return x + y;
};
f.count = 1;
// 等价于
type F1 = (a: number, b: number) => number;
// 这两者的区别,如果只是想简单声明函数就用下面F1这种,如果想要加属性,用上面一种
四. 函数的所有声明方式,这里主要关注函数的值和类型
- 回顾js中的三种函数写法
// js中函数的三种生命方式
// 1.函数声明
function f1(a) {}
// 2.函数表达式也叫匿名函数赋值
const f2 = function (a) {};
// 3.箭头函数
const f3 = (a) => {};
- ts中对应的写函数的方法
function f1(a: number): number {
return a + 1;
}
// 有两种写发对应js中的第二种声明方式
// 1. 写等号右边
const f2 = function (a: number): number {
return a + 1;
};
// 2. 写等号左边
type F2 = (x: number) => number;
const f2: F2 = function (a) {
return a + 1;
};
// 同样箭头函数也有两种对应写法
// 1. 写等号右边
const f3 = (a: number): number => {
return a + 1;
};
type F3 = (x: number) => number;
// 2. 写等号左边
const f3: F3 = (a) => {
return a + 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;
五. 两种特殊的函数
-
- 构造函数,后面再研究
-
- 类型谓词,之前文章有介绍过
// js自带的类型收窄
function f1(a: string | string[]) {
if (a instanceof Array) {
a;
} else {
a;
}
}
// 如果是对象类型
type Person = {
name: string;
};
type Animal = {};
function f2(a: Person | Animal) {
if (isPerson(a)) {
a; // a的类型被收窄为Person
}
}
// 注意:通过x is Person将函数和Person类型进行关联
function isPerson(x: Person | Animal): x is Person {
if ('name' in x) {
return true;
} else {
return false;
}
}
// 如果是箭头函数,那么类型只能写右边
const isPerson2 = (x: Person | Animal): x is Person => 'name' in x;
六. ts函数的一些细节
-
- 可选参数
function addEventListener(
eventType: string,
fn: unknown,
useCapture?: boolean
) {
// 浏览器实现
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?: boolean
) {
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;
const f = createAdd(6)(14); // 20
// 实际应用中的例子,Redux
// connect({map:{}}) (Component)