typescript 语法总结

typescript中的数据类型
1.基础类型 string,number,null,undefined,boolean

undefined:一个没被分配值的变量

null:人为分配一个空值

strictNullChecks: tsconfig.json中配置项,值为on时,在使用可能是null的值前,需要显示的检查

2.数组类型Array<T>,T代表数组中的元素类型(本写法要求元素类型统一)

3.any,unknown,noImplictAny

unknown:是any的替代品,将unknown类型变量赋值给其它类型变量时,会报错。

noImplictAny:(implict:隐式  inplict:显式):项目中是否允许隐式any,tsconfig.json中配置项

 

类型标注  let len:Number = 11;  //也可写成let len = 11,ts将进行类型推导               窄化??

函数:规定输入输出值类型

function greet(name:string):number{

  console.log(name)

}

匿名函数 contexture  typing:根据上下文猜测匿名函数参数的类型

const arr = ['frist','second','third'];

arr.forEach(function(s){  //匿名函数中当前项s,通过上下文推导出为string类型,所以支持toUpperCase方法

  console.log(s.toUpperCase())

})

联合类型:ts会针对联合类型做排除法,联合类型只能使用两个类型公共的方法。

function greet(name:string | number):number{

  // 只能使用传入类型公共的方法

  if(typeof name === 'string'){  console.log(id);  return;}

  console.log(name.toUpperCase());

 }

类型别名type:支持多种类型组合(&),可以简单理解为字符串的替换
type id=number | string;

type Point = {x:name;y:number;}

type Bear = Point & {honey:boolean}  //多种类型组合(&)

let uid :id = 100  //可以简单理解为字符串的替换, typeof uid 会返回number而不是id

type更多用法:
type StringOrNumber = string | number;
type Text = string | { text: string };
type NameLookup = Dictionary<string, Person>;
type Callback<T> = (data: T) => void;  // 对T进行Callback操作
type Pair<T> = [T, T];
type Coordinates = Pair<number>;
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
 

接口interface:支持继承extends,接口被定义两次时定义的属性会合并(但相同属性不能更改类型,高阶能力)

interface Point{ x:name;y:number;  }

interface Bear extends Point{   honey:boolean }  //继承

类型别名和接口,都可以按以下方式调用:
const bear1:Bear = {
    x:12,
    y:'lele'
}
console.log(bear1)
 
 更多知识见 《typescript中的interface和type到底有什么区别详解》https://www.jb51.net/article/163299.htm
 

类型断言assertion,只是提示作用

const x = 'hello' as number // 可使用 const x = ('hello' as unknown) as string  来欺骗ts

html元素对应的接口名称  https://www.cnblogs.com/liuxu-xrl/p/15401274.html

 

字面类型:常量const的值为字面值,不能修改。相对于let 。

可以用字面类型约束一些特殊的函数:

interface options {
    id:number
}
// 字面类型
function configure(x:options | 'auto'){
    console.log(x)
}
configure('auto');
configure({id:1});
configure('');  //类型“""”的参数不能赋给类型“options | "auto"”的参数。
 
字面类型的坑点:只能处理当前一级传值

function handleReq(url:string,method:"GET"|"POST"){
    console.log(url,method)
}
const req = { url:'http://abd.com',method:"GET" };
// handleReq(req.url, req.method);   // 报错类型“string”的参数不能赋给类型“"GET" | "POST"”的参数。
正确写法0:
handleReq(req.url,"GET")
正确方法1:
handleReq(req.url,req.method as "GET")
正确方法2:
const req2 = { url:'http://abd.com',method:"GET"  as "GET"};
handleReq(req.url,req.method)
正确方法3:
const req2 = { url:'http://abd.com',method:"GET"} as const;
handleReq(req2.url,req2.method)
 
js对象逃避类型检查方式
strictNullChecks:true时,需要显式的检查可能是null的值
function doSomeThing(x:string | null){
    console.log("hello,"+x.toUpperCase());     //报错: 对象可能为 "null"。
    console.log("hello,"+x!.toUpperCase());     // 可以用!操作符,来断言某个值不是空值
}
 
枚举类型 enum:枚举类型默认会返回数字,支持反向取属性(也可以赋值为字符串,但是没必要,因为可以反向获取;也可以混合不同的数据类型,但是会增加复杂度)
enum Direction {
    up=1,
    down,
    left,
    right
}
console.log(Direction.down,Direction.left)  //2 3 返回数字
console.log(Direction[Direction.left])  //left   反向操作提取Enumerate中的字符串(属性名称),也叫Reverse Mapping
function f(obj:{up:number}){
  return obj.up
}
f(E)
f({up:1,down:2})  // Error 类型“{ up: number; down: number; }”的参数不能赋给类型“{ up: number; }”的参数。对象文字可以只指定已知属性,并且“down”不在类型“{ up: number; }”中。
 
泛型:一种抽象一类事物的共性特征的编程手段,它允许将类型作为其它类型的参数(表现形式),从而分离不同关注点的实现(作用)。泛型可以根据传入的函数的参数,自动推导出泛型类型和函数返回值类型。
关注点(interest Point)不同:程序里有三种表达:
接口interface:一种方面的描述,一个类型可以拥有多个方面的特性
继承inheritance:一种强表达。松树->extends->树
泛型Generics:是对共性的提取。e.g 在造床这件事务上,桃木,红木等等木头都有这个作用
e.g
 
// 以下方式,只能处理number类型
function identity1(arg:number):number{
    return arg;
}

// 泛型函数
// 通过钻石操作符<>,传入泛型的参数,结合函数的参数(类型)和函数的返回值类型,帮我们支持所有类型
function identity2<Type>(arg:Type):Type{
    return arg
}
let out2 = identity2<string>('MyString');   //等价于 let out = identity2('MyString');  此时,可以通过值推导出传入值类型
// out2 = 100; //不能将类型“number”分配给类型“string”。

// 泛型类
class GenericNumber<T>{
    private zeroValue:T;
    constructor(v:T){
        this.zeroValue = v;
    }
    public add(x:T,y:T){
        return this.zeroValue + '' + x + y;  //运算符“+”不能应用于类型“T”和“T”。=> 因为仅数字能进行运算
    }
}
let gener = new GenericNumber<string>('hello,');
console.log(gener.add('Lucy','Lily'));  //hello,LucyLily

// extends interface 给泛型添加约束
interface Lengthwise{
    length:number
}
function loggingIdentity<Type extends Lengthwise>(arg: Type):Type{  // 让Type继承Lengthwise以支持.length
    console.log(arg.length);  // <Type extends Lengthwise>改成<Type>时,因不确定Type类型,所以找不到.length属性,导致报错
    return arg
}
loggingIdentity<string>('test')  // 也可简写为 loggingIdentity('test') ,通过传入值自动推导Type

// type keyof 给泛型添加约束
type Point = {x:number;y:number}
type P = keyof Point;   //P = 'x' | 'y',即Point中所有的参数(属性)

function getProperty<Type,Key extends keyof Type>(obj:Type,key:Key){
    console.log(obj[key])
    return obj[key]
}
let x1 = {a:1,b:2,c:3,d:4}; //因为是静态的,所以可以用keyof操作符获取所有的key,若对象x1的类型为any,那么keyof就没有意义了
// x1.z= 10;  // 类型“{ a: number; b: number; c: number; d: number; }”上不存在属性“z”。
getProperty(x1,"d")
// getProperty(x1,"m") //类型“"m"”的参数不能赋给类型“"d" | "a" | "b" | "c"”的参数。
实例化泛型类型,将类作为参数传入
function create<Type>(c:{new ():Type}):Type{  // 也可写为function create<Type>(c:new ()=>Type):Type{
  return new c();
}
create(Foo)  //返回Foo的实力
e.g 实战实例
class BeeKeeper {
    hasMask : boolean = true;
}
class ZooKeeper {
    nametags: string = 'Mikle';
}
class Animal {
    numLegs : number = 4;
}
class Bee extends Animal{
    keeper:BeeKeeper = new BeeKeeper();
}
class Lion extends Animal{
    keeper:ZooKeeper = new ZooKeeper();
}
function createInstance<A extends Animal>(c: new()=>A):A{
    return new c();
}
console.log( createInstance(Lion).keeper.nametags );  //返回一个
console.log( createInstance(Bee).keeper.hasMask );
 
窄化(Type Narrowing)本质是重新定义类型,解决联合类型校验的问题
 if + typeof:
typeof返回值类型:string","number","bigint","boolean","symbol","undefined","object","function"。注意typeof null==='object'
真值窄化:帮我们更好的应对null,undefined,0等情况的判断
JavaScript真值表(if时会进else的):0,null,undefined,NaN," "(the empty string),0n(the bigint version of zero)
相等性窄化:隐式的窄化方法,相等性窄化。===,!==,== ,and != 都可以用来窄化类型。
interface Container{
    value:number | null | undefined;
}
function mulValue(container:Container,factory:number){
    if(container.value !=null){  //此处!=可以过滤掉null,undefined两种类型(!=两侧的 undefined和null都会转成false )。如果替换为!==,会报错 ,因为到时Container.value为 numberundefined
        container.value *= factory;
        return container.value
    }
    return container.value;
}
//number类型
let data = mulValue({value:10},2);
console.log(data)
//null或undefined类型
let data2 = mulValue({value:undefined},2);
console.log(data2)
 
in操作符窄化(type定义时)
type Fish = { swim:()=>void };
type Bird = { fly:()=>void };
function move(animal:Fish | Bird){
    if('swim' in animal)    return animal.swim();
    else animal.fly()
}
class myFish{
    public swim(){
        return 'swim'
    }
}
console.log(move(new myFish()));

// instanceof 做窄化
// 此处Date必须是真实存在的Function类型,不能是type
function move1(time: Date | string){
    if(time instanceof Date){
        console.log('time',time)
        return 'time'
    }
}
move1(new Date());
 
组合类型推导
let x = Math.random() < 0.5 ? 10: "hello world!"; // 系统会自动推导出x为number或string类型
// xx = new Date() //Error 不能将类型“Date”分配给类型“string | number”。  因为ts推导出 只能赋值为number或string类型
 
 
控制流分析:
ts是如何做窄化的?在语法分析阶段,ts编译器识别出类型卫兵表达式(e.g if(typeof padding === 'number' ) 、instanceof).然后对返回值逻辑分别做窄化,窄化的本质是重新定义类型。
// 控制流窄化
function exp1(){
    let  x  :string | number | boolean;
    x = Math.random()>0.5;  // boolean
    if(Math.random()<0.5){
        x='hello';  // string
        console.log(2,typeof x);
    }
    else{
        x = 100;    // number
        console.log(3,typeof x);
    }
    return x;   //string | number,没有Boolean了,因为上面的if,else语句已经把Boolean的可能干掉了
}
exp1();
 
 
断言操作符:
Assertion操作符as:提示ts某种类型是什么,当用户比ts更了解类型时使用,as影响的是当前函数内部
predicate操作符is:用户自定义的类型守卫,用于帮助Typescript Narrowing  ,is影响的是当前函数的调用逻辑,函数内无效
function isFish(pet:Fish | Bird) : pet is Fish {
    // return pet.swim !== undefined  // Error 类型“Bird”上不存在属性“swim”,因为pet is Fish
    return (pet as Fish).swim !== undefined;  //内部窄化逻辑
}
let pet = {
    fly:()=>{}
}
if(isFish(pet)){
    pet.swim()  //上面有了 pet is Fish,才不报错 Bird无swim方法
}
else pet.fly();
 

判别的联合窄化(Discriminated unions)
interface Circle{  // 圆
    kind:'circle';
    radius:number;
}
interface Square{   //方形
    kind:'square',
    sideLength:number;
}
type Shape = Circle | Square;
// 计算面积
function getArea(shape : Shape){
    switch(shape.kind){
        case 'circle':
            return Math.PI * shape.radius ** 2; // ** 平方
        case 'square':
            return shape.sideLength ** 2;
    }
}
 
Nevel:不应该出现的类型
interface Circle{  // 圆
    kind:'circle';
    radius:number;
}
interface Square{   //方形
    kind:'square',
    sideLength:number;
}
interface Trips{
    kind:'trips';
    value:number
}
type Shape = Circle | Square | Trips;
// 计算面积
function getArea(shape : Shape){
    switch(shape.kind){
        case 'circle':
            return Math.PI * shape.radius ** 2; // ** 平方
        case 'square':
            return shape.sideLength ** 2;
        default:
            const _value:never = shape; // Error 不能将类型“Trips”分配给类型“never”。
            return _value;
    }
}
 
inter 类型推导
// e.g 提取多层数组里的值
type Flatterned<T> = T extends Array<infer V>?Flatterned<V>:T;
function flattern<T extends Array<any>>(arr:T):Array<Flatterned<T>>{
    return (new Array()).concat(...arr.map(x=>Array.isArray(x)?flattern(x):x))
}
let val = flattern([1,2,4,[5,[6,[7,[[[9]]]]]]]);
console.log(val)  // [1, 2, 4, 5,6, 7, 9]
posted @ 2021-10-13 11:14  liuxu_xrl  阅读(1389)  评论(0编辑  收藏  举报