本篇文章只是为了记录易漏知识点,并不过多过全的说 typescript —–只针对个人
const arr:Array<number>=[1,2,3,4,5];
const arr2:number[]=[1,2,3,4,5];
// 元组
const arr2:[string,number]=['duanxl',26]
// 元组定义
interface Tuple extends Array<string | number> {
0:string;
1:number;
length:2;
}
// 元组越界问题
const tuple:[string, number]=['duan',26];
tuple.push(99);
console.log(tuple) // ['duan',26,99]
console.log(tuple[2]) // Tuple type '[string, number]' of length '2' has no element at index '2'. ts(2493)
// 静态类型的原因
// 枚举编译后
var Direction;
(function(){
Direction[Direction['top']=10]='top';
Direction[Direction['bottom']=20]='bottom';
Direction[Direction['left']=30]='left';
Direction[Direction['right']=40]='right';
}(Direction || Direction={}))
// example
Direction.top // 10
Direction[Direction.top] // 'top'
enum Direction {
Left,
Right,
Top,
Bottom
}
enum Food{
Hotdog,
Meat
}
let a:Direction;
a=Direction.Left;
a=Food.Hotdog; //Type 'Food.Hotdog' is not assignable to type 'Direction'.ts(2322)
// 值虽然一样,但是类型不一样
接口主要是对值所具具有的解构进行类型检查,也可以说是值的定义规则
类主要是通过继承,接口是组合,组合大于继承,在设计模式里,组合更加易于维护,但是如果你想初始化一个带有默认值的复杂类型,建议使用类作为接口
由于很少使用泛型 extends、keyof 等关键字,再次回顾
function getValue<T extends object,U extends keyof T>(obj:T,key:U){
return obj[key]
}
function makeType<T>(type:{new() : T}):T{
return new type()
}
交叉类型是将多个类型合并成一个类型
function formatCommandLine(command:string[]|string){
let line='';
if(typeof command === 'string'){
line=command.trim()
}else{
line=command.join(' ').trim();
}
}
function mixin<T entends object,U extends object>(first:T,second:U):T & U{
const result=<T & U>{};
for(let id in first){
(<T>first)[id]=first[id]
}
for(let id in second){
if(!result.hasOwnProperty(id)){
(<U>result)[id]=second[id]
}
}
return result
}
type some=boolean | string;
type Direction='Month' | 'Year' | 'Day';
const hello:'hello'='world' // error
与 JavaScript 中的对象字面量相似
type Foo {
baz:[
number,
'duanxl'
],
toString():string;
readonly [Symbol.iterator]: "duanxl's blog";
}
type usserAction {
id: number;
action: 'delete';
info: Info
} |
{
action: 'create';
info: Info
}
类型断言
我们知道断言可以使用 User
,也可以使用”as”
双重断言
interface Person{
name:string;
age:number;
}
const person='duanxl' as Person; // error
const person = 'duanxl' as any as Person; // success
// 一般用于欺骗编译器。。。
类型守卫
主要用于缩减类型范围
interface Person{
name:string;
age:number;
}
interface Animal{
name:string;
color:string;
}
function getInfo(arg: Person | Animal){
if(arg instanceof Person){
console.log(arg.color) // error
console.log(arg.age) // success
}
}
function getInfo(arg: Person | Animal){
if('age' in arg){
console.log(arg.color) // error
console.log(arg.age) // success
}
}
如果 x 要兼容 y,那么 y 至少要具有 x 相同的属性。即短的兼容长的,反过来则不行
class Person {
constructor(public weight: number, public name: string, public edu: string){}
}
interface Dog {
name:string;
weight:number;
}
let x:Dog;
x = new Person(120,'duanxl','bk') // success
与上面的类型兼容性相反,如果 x 要兼容 y,那么 y 的参数及类型包含 x 的参数类型
let fn1=(a: number)=>0;
let fn2=(b:number,c:string)=>0;
fn2=fn1 // success
fn1=fn2 // Error
与类型兼容性相似,只是类的兼容性仅比较实例成员和方法,不会比较构造函数和静态成员
class Person{
name: string;
constructor(name:string,age:number){
this.name=name;
}
}
class Animal{
name:string;
constructor(name:string){
this.name=name;
}
}
let p:Person= new Person('duanxl',26);
let a:Animal=new Animal('pig');
p = a // success
a = p // success
与上面的类型守卫相似,也用于缩短范围
function isString(test:any):test is string{
return typeof test==='string';
}
function example(foo: number | string){
if(isString(foo)){
console.log(foo.length) // success
}else{
console.log(foo)
}
}
interface Func {
(): string;
new (): string;
}
declare const toAnyString: Func;
toAnyString();
new toAnyString();
/**
* 简单实现一个从对象里得到属性值的方法
*/
const user = {
user: "duan",
age: 26,
id: "xxxx",
role: "vip",
};
// 简陋版
interface Obj {
[key: string]: any;
}
function getValue(o: Obj, names: string[]) {
return names.map((item) => o[item]);
}
// keyof 版
function getValue2<T, U extends keyof T>(o: T, names: U[]): T[U][] {
return names.map((item) => o[item]);
}
getValue(user, ["aa", "bb"]); // 无静态限制
getValue2(user, ["user", "role"]); // 有静态限制
假如我们要将一个类型进行扩展,但是不需要类型中的所有属性,那么我们可以把类型变成可选的,可以理解为 for … in 循环
type Person<T> = { [K in keyof T] ?: T[K] }
用法和我们的三元运算差不多,关键字:extends
最简单的类型编程。。。
declear function fn<T extends boolean>(x : T):T extends true ? string : number;
const fn1 = fn(Math.random() < 0.5);
const fn2 = fn(false) // number
const fn3 = fn(true) // string
// 很遗憾,技术还没到写架构接口这块。。。
只考虑 T 存在一种类型
// 没有任何参数被数组包裹
type TypeOne<T> = T extends boolean ? 'yes' : 'no';
考虑 T 存在可选类型
// 类型参数被数组包裹
type TypeTwo<T> = [T] extends [boolean] ? 'yes' : 'no'
如果存在多个类型参数,且都是联合类型
type Diff<T, U> = T extends U ? never : T;
type R = Diff<"a" | "b" | "c", "d" | "b" | "f">; // "a" | "c"
// example2:
type Filter<T , U> = T extends U ? Y :never;
type R1 = Filter<string | boolean | (()=>void) , Function>; // ()=>void
假如我们把泛型想象成对象字面量,那么我们如何将 interface 函数类型的名称取出来
interface Part {
id: string;
name: string;
subParts: Part[];
updatePart(newVal: string): void;
}
interface Part2 {
id: string;
name: string;
subParts: Part[];
updateParts(x: Part): void;
}
type GetFunctionTypes<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type Res=GetFunctionTypes<Part> // "updatePart"
可以理解成摘取成中间类型
/**
* 我们现在实现一个字面量类型转换
* 即 [string,number] --> string | number
*/
type Type1 = [number, string];
type ElementOf<T> = T extends Array<infer T> ? T : never;
type Res = ElementOf<Type1>; // string | number
加深影响,下面的 infer,我们可以继续想象成摘取
对应类型,则 infer P 即代表摘取到的返回类型
interface User {
id: string;
name: string;
form?: string;
}
type Foo = () => User;
type Return<T> = T extends (...args: any[]) => infer P ? P : any;
type Res = Return<Foo>; // User
typeof,类型保护
typeof,对于值,与 JavaScript 一样,返回字符串的类型值,对于 class,可以理解成将 class 的类型映射出来
class Person{
constructor(name:string,age:number){}
}
type Type=typeof Person;
// new(name:String,age:number)=>any:
再次加深,typeof 与 infer 的使用
class Person {
constructor(name: string, age: number) {}
}
type Type = typeof Person;
type ConstructorParamers<
T extends new (...args: any[]) => any
> = T extends new (...args: infer P) => any ? P : never;
type Res = ConstructorParamers<Type>; // [name:string,age:number]
type Foo=Omit<{name:String,age:number},'name'> // {age:number}
type Record<K extends keyof any, T> = {
[P in K]: T;
};
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
type Exclude<T, U> = T extends U ? never : T;