目录
Contextual Typing【上下文映射,上下文类型】
构造函数表达
type SomeConstructor = {
new (s: int):String
}
function fn(ctor: SomeConstructor) {
return new ctor("hello")
}
const str = fn(String)
console.log(str) // hello
泛型和函数
泛型函数
function firstElement<Type>(arr: Type[]):Type {
return arr[0]
}
Contextual Typing【上下文映射,上下文类型】
// map : a -> b
function map<Input, OutPut>(arr: Input[], func: (arg: Input) => Output): Output[] {
return arr.map(func); // Output[]
}
const parsed = map(["1", "2", "3"], (n) => parseInt(n))
// [1,2,3]
泛型约束
function minimumLength<Type extends { length: number }>(
obj: Type,
minimum: number
): Type {
if (obj.length >= minimum) {
return obj;
} else {
return { length: minimum };
// 不能将类型“{ length: number; }”分配给类型“Type”。
// "{ length: number; }" 可赋给 "Type" 类型的约束,
// 但可以使用约束 "{ length: number; }" 的其他子类型实例化 "Type"
}
}
手动指定类型
function combine<Type>(arr1: Type[], arr2: Type[]):Type[] {
return arr1.concat(arr2);
}
const arr = combine([1,2,3], ["hello"]);// Error 不能将类型“string”分配给类型“number”。
const arr2 = combine<string | number>([1,2,3],["hello"]) // 手动指定string | number
泛型的使用规范
// 泛型的参数越简化越好,最少支持原则,高效,参数少
function firstElement1<Type>(arr: Type[]) { // 更简单 √,方便阅读
return arr[0];
}
function firstElement2<Type extends any[]>(arr: Type) {
return arr[0]
}
对比
对比下一组,哪个更好?
function filter1<T>(arr: T[], func: (arg: T) => boolean): T[] {
// √ 泛型参数少,读起来方便
return arr.filter(func);
}
function filter2<T, Func extends (arg: T) => boolean>(arr: T[], func: Func): T[] {
// Func这个泛型没有必要
return arr.filter(func);
}
可选参数
function myForEach(arr: any[], callback: (arg: any, index?:number)=> void){
// 可选参数index?:
for (let i = 0; i < arr.length; i++) {
callback(arr[i], i);
}
}
思考:onClick中e的设计
<div onClick={ e=>{} }></div> // e是可选参数
<div onClick={ ()=>{} }></div> // e是可选参数
函数重载
function add3<T> (a: T, b: T ) {
return a + b // Error 运算符“+”不能应用于类型“T”和“T”。
}
// a,b不一定可以相加
// 函数的重载,可多次,基础方法
function add(a:number,b:number); // add(1,2)
function add(a:string,b:string); // add("1","2")
function add(a:number,b:string); // add(1,"2")
function add(a:string,b:number); // add("1",2)
function add(a:string); // add(1)
function add(a: any,b?:any) {
if(!b) {
b = 1
}
return a + b
}
修改办法
function isSet<T>(x: any): x is Set<T> {
return x instanceof Set
}
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add<T>(a: Set<T>, b: Set<T>): Set<T>;
function add<T>(a: T, b: T): T {
if (isSet<T>(a) && isSet<T>(b)) {
return new Set([...a, ...b]) as any
}
return (a as any) + (b as any)
}
const a = new Set<string>(["apple", "redhat"])
const b = new Set<string>(["google", "ms"])
console.log(add(a, b))
console.log(add(1, 2))
console.log(add("a", "k"))
操作符重载
THIS
interface DB {
exec(sql: string) => any
}
function runSql(this: DB, sql: string) {
this.exec(sql)
}
runSql.bind(new DB()).("select * from user")
void【空返回值】
// void
type voidFunc = () => void;
const f1: voidFunc = () => {
return true;
}
const f2: voidFunc = () => true
const f3: voidFunc = function () {
return true;
}
思考为什么这样写?
function safeParse(s: string): unknown { // 比any安全
return JSON.parse(s); // as 断言;断言之前,unknown值是不能直接赋值给其他变量的
}
Rest params
// JS本身有这个方法
function multiply(n: number, ...m: number[]) {
return m.map((x) => n * x);
}
// 无法重新声明块范围变量“a”。
const a = multiply(10, 1, 2, 3, 4);
小结
- 重新思考泛型的作用?提供对共性的抽象,// add , filter
- 思考函数重载的意义?为函数提供了更严格的类型检查方式,能让真正使用any这样的函数,作为参数,把它窄化,更精确的类型去表达,所有函数调用的类型都是准确的