重学TypeScript,基础归纳

268 阅读4分钟

2021-05-29 TypeScript 基础归纳

重学TypeScript,基础归纳

1. 数据类型

1.1 8个js中常见的数据类型

  • number
  • string
  • boolean
  • null
  • undefined
  • arrary
  • object
  • symbol

1.2 ts中补充的8个类型

  • 元祖
  • any(不要滥用any)
  • unknown,相对于any来说这个是安全的[与any的区别,这里主要说一下使用上的区别,被声明为unknown的数据不可以直接使用.属性和对其赋值]
  • 枚举enum
  • void,与any相反,表示没有类型(void 类型的变量只能赋值为 undefined 和 null ,其他类型不能赋值给 其他类型不能赋值给 void 类型的变量)
  • never ,指那些永不存在的值的类型,它是那些总会抛出异常或根本不会有返回值的函数表达式的返回值类型[ 例如返回一个 new Error()]
  • 交叉类型

交叉类型就是取多个类型的并集,使用 &符号定义,被&符链接的多个类型构成一个交叉类型,表示这个类型同时具备这几个连接起来的类型的特点

const merge = <T,F>(a:T,b:F):T&F=>{
    return{
        ...a,
        ...b
    }
}
merge({name:'test'},{age:25})
  • 联合类型

联合类型实际是几个类型的结合,但是和交叉类型不同,联 合类型是要求只要符合联合类型中任意一种类型即可,它使用|符号定义。当程序具有多样性,元素类型不唯一时,即使用联合类型。 let a:string|number = 3 // 这就是一个联合类型,表示a既可以是string或number

2.断言

一般一个类型的断言就是:

let a as string = '2' 什么情况下使用断言呢?就是在我们明确该数据类型是什么的时候就可以使用断言

3. 使用interface接口定义数据类型结构

3.1 普通接口类型定义

interface peopleProps{
    name:string
    age:number
}
let a:peopleProps = {
    name:'tangjie',
    age:18
}

这种结构定义的接口能a.name或者a['name']却不能let name_var = 'name';a[name_var]去取值,这在我们动态去对象值是很不友好的

3.2 可动态取值的接口

interface peopleProps{
    [index:string]:string|number
    name:string
    age:number
}

3.3 只读属性的接口

在属性前使用readonly修饰

interface peopleProps{
    [index:string]:string|number
    readonly name:string
    age:number
}

3.4 函数式类型接口

接口也可以为函数定义类型

interface addFun{
    (num1:number,num2:number):number
}

const addFuns:addFun = (a,b)=>{
    return a+b
}

console.log(addFuns(1,1))

3.5 混合类型接口

一般这个用于函数和闭包设计,列如我希望,一个变量即是一个函数,有同时有其属性,代码如下

interface addFun{
    count:number,
    (num1:number,num2:number):number
}
const addFuns:addFun = (():addFun=>{
    const c = (num:number,num2:number)=>{
        return num+num2
    }
    c.count = 1
    return c
})()

3.6 继承接口

接口可以用extends关键字去继承其属性类型

3.7 注意点,ts是面向接口编程

ts是面向接口编程,不是面向对象编程,嗯,听起来是不是很模糊,这是啥?为了方便理解直接上一个例子:

interface exampleA {
    id:string;
    createTime:string;
}

const testFn = ( a:exampleA ) =>{
    console.log( a )
}

const a:exampleA = {
    id:'1',
    createTime:'2021/02/03'
}

testFn(a)
testFn({
    id:'2',
    createTime:''
})

从上面例子可以看出来 testFn 函数并不需要入参的数据要被声明成exampleA类型的接口,而是形如exampleA的接口即可

4. 泛型

4.1 泛型约束

泛型约束使用和interface继承一样的关键字extends

4.2 在泛型约束中使用类型参数

const getProp = <T, K extends keyof T>(object: T, propName: K) => {
  return object[propName];
};
const obj = { a: "aa", b: "bb" };
 // 类型“"c"”的参数不能赋给类型“"a" | "b"”的参数
getProp(obj, "c");

5 类型别名

5.1 类型别名中使用泛型

type testType<T,S> = {
    x:T,
    y:S
}
const a:testType<string,number> = {
    x:'xxxx',
    y:3
}

6 索引类型查询操作符

// 这里使用泛型,并且约束泛型变量K的类型是"keyof T",也就是类型T的所有字段名组成的联合类型
function getValue<T, K extends keyof T>(obj: T, names: K[]): T[K][] { 
  // 指定getValue的返回值类型为T[K][],即类型为T的值的属性值组成的数组
  return names.map(n => obj[n]);
}
const info = {
  name: "lison",
  age: 18
};
let values: string[] = getValue(info, ["name"]);
// error 不能将类型“number[]”分配给类型“string[]”
values = getValue(info, ["age"]);