第一次写,总感觉这没准备好,那没准备好,哪有都准备好了的,干就完事
准备工作
克隆项目 git clone https://github.com/lxchuan12/vue-next-analysis.git
计划了解的
主要要啃的是 packages\shared\src 下的函数
一个个来看下
正餐
is的用法
export const isArray: (arg: any) => arg is any[] = Array.isArray // 首先这是TS的语法 等价于 export const isArray = Array.isArray 这种写法与 : export const isArray: (arg: any) => boolean = Array.isArray 有什么区别吗,看下面这两个例子 function isString(test: any): test is string{ return typeof test === "string"; } function example(foo: any){ if(isString(foo)){ console.log("it is a string" + foo); console.log(foo.length); // string function // 如下代码编译时会出错,运行时也会出错,因为 foo 是 string 不存在toExponential方法 console.log(foo.toExponential(2)); } // 编译不会出错,但是运行时出错 console.log(foo.toExponential(2)); } example("hello world"); // -------------------------------- function isString(test: any): boolean{ return typeof test === "string"; } function example(foo: any){ if(isString(foo)){ console.log("it is a string" + foo); console.log(foo.length); // string function // foo 为 any,编译正常。但是运行时会出错,因为 foo 是 string 不存在toExponential方法 console.log(foo.toExponential(2)); } } example("hello world"); 在使用类型保护时,TS 会进一步缩小变量的类型。 例子中,将类型从 any 缩小至了 string 类型保护的作用域仅仅在 if 后的块级作用域中生效
keyof
const hasOwnProperty = Object.prototype.hasOwnProperty export const hasOwn = ( val: object, key: string | symbol ): key is keyof typeof val => hasOwnProperty.call(val, key)
这里没学过ts的同学可能有点晕,这个is刚刚上面讲过了是做类型保护的,那这个 keyof typeof 又是啥 这个val又是啥
别急,跟我一个个来
首先先看这个 keyof
keyof 操作符是在 TypeScript 2.1 版本引入的, 该操作符可以用于获取某种类型的所有键,其返回类型是联合类型。 interface Person { name: string; age: number; location: string; } type K1 = keyof Person; // "name" | "age" | "location" type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ... type K3 = keyof { [x: string]: Person }; // string | number 除了接口外,keyof 也可以用于操作类 class Person { name: string = "Semlinker"; } let sname: keyof Person; sname = "name"; keyof 操作符除了支持接口和类之外,它也支持基本数据类型 let K1: keyof boolean; // let K1: "valueOf" let K2: keyof number; // let K2: "toString" | "toFixed" | "toExponential" | ... let K3: keyof symbol; // let K1: "valueOf" 此外 keyof 也称为输入索引类型查询,与之相对应的是索引访问类型,也称为查找类型。 在语法上,它们看起来像属性或元素访问,但最终会被转换为类型: type P1 = Person["name"]; // string type P2 = Person["name" | "age"]; // string | number type P3 = string["charAt"]; // (pos: number) => string type P4 = string[]["push"]; // (...items: string[]) => number type P5 = string[][0]; // string 所以简单的抓住重点返回的是key 举个简单的例子 // js function getProperty(obj, key) { return obj[key]; } // 这个转成ts怎么写尼 function getProperty(obj: object, key: string) { return (obj as any)[key]; } // 不太优雅,用上keyof function getProperty<T extends object, K extends keyof T>(obj: T, key: K) { return obj[key]; } function getProperty<我是对象 extends object, 我是对象中的键 extends keyof 我是对象>(obj: 我是对象, key: 我是对象中的键) { return obj[key]; }
这时候聪明的同学就要问了 老师,这个extends你还没讲呀
这个 extends 要和 keyof 连在一起看,至少按我的理解是的
keyof T 是 T 类型的键集
extends是子集的意思
子类型的值一定也是父类型。比如“猫”是“动物”的子类型,一只具体的 “猫”一定也是“动物”
所以父类型是 ‘a’|’b’ 子类型只能是 <= 父类型的
extends keyof 和 in keyof 要区分看
function getProperty<T extends object, K extends keyof T>(obj: T, key: K) { return obj[key]; } // 这里的意思是K必须是T的公共属性名称,与class的那个extends 意思不太一样甚至相反 interface Person { age: number; name: string; } // 每一项映射成了可选的 type Optional<T> = { [K in keyof T]?: T[K] }; const person: Optional<Person> = { name: "Tobias" }; // 看上去这个 Optional<Person> 和 Person 一模一样是吧 // 我这边的理解是 这是一种映射 从必填都变成了可选 type ReadOnly<T> = { readonly [K in keyof T]: T[K] }; const readperson: ReadOnly<Person> = { name: "Tobias", age:18 }; readperson.age = '' // Cannot assign to 'age' because it is a read-only property. 就是这样 还不明白看看这个 type 可选的<未知> = { [键 in keyof 未知]?: 未知[键] }; type 可选的<未知> = { [键 in keyof 未知]?: 未知[键] }; const readperson: 可选的<Person> = { name: "Tobias", };
总结下
A extends keyof B
表示 A 是B 的子类型
in 是遍历的意思
Record
type Record<K extends keyof any, T> = { [P in K]: T; }; export const isObject = (val: unknown): val is Record<any, any> => val !== null && typeof val === 'object' export const isFunction = (val: unknown): val is Function => typeof val === 'function' export const isPromise = <T = any>(val: unknown): val is Promise<T> => { return isObject(val) && isFunction(val.then) && isFunction(val.catch) }
又有小可爱问了:这个Record是什么意思呀
看不懂没关系下次再讲
扩展
值得注意的点
1、is 在 TS 中可以用来类型保护,缩小返回
2、keyof , extends keyof , in keyof