美文网首页
typescript基本类型与语法

typescript基本类型与语法

作者: 卡拉咖啦 | 来源:发表于2019-12-01 15:19 被阅读0次
    let a: string = "abc" // 规定值的类型
    function fn(arg: number): number { //这里规定了参数 arg 的类型以及函数返回的类型
        return arg + 1
    }
    

    目录

    • ts基本类型
      • js 的七种基本类型
      • Enum
      • Any
      • Void
      • Tuple
      • Null & Undefined
    • 数组类型
    • 伪数组类型
    • 函数类型
      • this
      • 重载
      • 描述一个函数
    • 接口 interface
      • 基本用法
        • 只读属性
        • 可选属性
        • 方法
        • 任意属性
      • 获取接口的属性类型
    • 继承 extends
    • 类 class
      • 类的继承
      • 修饰符
        • public
        • private
        • protected
        • get / set
        • static
      • 抽象类
    • 语法 & 关键字
      • Partial
      • type
      • keyof
      • in
      • [ ]
      • &
      • |
      • Readonly
      • Partial
      • declare
    • 类型断言(类型转换)
      • < >
      • as
    • 其它
      • 类型兼容
      • soundness
      • 用 ts 添加 window 变量
      • 给 React 添加全局属性

    内容

    ts 的基本类型

    js 的七种基本类型:
    string, number, null, undefined, object, symbol, boolean

    其它:
    enum, any, void

    enum 枚举
    //申明一个枚举 Gender
    enum Gender {
        Man = 'man', //这里给 Man 设置了值,默认情况下(不写 = 'man')是 0,
        Woman = 'woman',
    }
    // 使用:
    let a: Gender = Gender.Man //使用的时候,就直接用 枚举名称.key 的格式,就不会写错。
    
    any

    表示任何类型

    Void 空类型
    function fn(arg: number): void { 
        //不写 return 
    }
    
    Tuple

    规定了一个 数组 的 item 类型

    // Declare a tuple type
    let x: [string, number];
    // Initialize it
    x = ["hello", 10]; // OK
    // Initialize it incorrectly
    x = [10, "hello"]; // Error
    
    Null & Undefined

    undefined(null) 可以理解为 空,默认情况下null和undefined是所有类型的子类型。就是说你可以把 null和undefined赋值给任何类型的变量。

    在 ts 中,null 与 undefined 没有区别

    let a: string = undefined // 可以
    

    数组

    list1: Array //数组
    
    list2: Array<number> //数字组成的数组
    list3: number[] // 等价于上面
    
    list4: Array<Array<number>> // 数字组成的数组所组成的数组 ……
    list5: number[][] //等价于上面
    

    ArrayLike

    伪数组的定义(源码):

    interface ArrayLike<T> {
        readonly length: number;
        readonly [n: number]: T;
    }
    

    函数

    function fn(arg1: string, arg2 = 2): void{
        //arg2 可以不写类型,ts 会自动知道是 number
        //...
    }
    
    this

    我们可以规定 this 的类型:

    interface Human {
        name: string;
        age: number;
    }
    
    function fn(this: Human){
        console.log(this)
    }
    
    fn.call({name: 'abc', age: 18}) // 前面规定了 this 必须是符合 Human 的对象,所以这里必须用 call,
    fn() // 会报错
    

    注意,ts 语法中,函数的参数数量必须与声明时一致。

    重载

    指的是一个函数有不同的调用形式

    //重载,要么满足第一个,要么满足第二个
    function add(n1: number, n2: number);
    function add(n1: string, n2: string);
    function add(n1, n2) { // 最后这个函数只是实现,不代表“接受任何参数”
        return n1 + n2
    }
    

    重载优于泛型的地方:
    重载可以规定某几种,但是泛型似乎做不到 …… 泛型太泛了 ……

    描述一个函数:

    (写法与普通对象不一样)

    interface Fn {
        (a: string, b: string): string; //注意,这里的 a / b 没有什么意义,我们在后面创建一个函数的时候,不一定要用这两个名字
    
        hi(): void // 这个是这个函数的方法
    }
    
    //但是,这样的规范,使得我们想要给一个函数加上属性方法,变得不容易,比如,上面我们给函数描述了一个 hi 方法,但是我们如何用呢?
    
    let fn: Fn = (
      (): Fn => { // 这个箭头函数的意思是,你会返回一个符合 Fn 描述的函数,所以 fn 得到的就是这个箭头函数返回的(符合描述的)函数
        let x: any = function(a: string, b: string): string {
          return a + b
        }
        x.hi = function(): void {
          return 1
        }
        return x
      }
    )()
    
    

    interface

    接口(interface)就是用代码描述一个对象必须有什么属性(包括方法),不能少,也不能多

    interface XXX {
      abc: number;
      readonly name: string;  // 只读 readonly
      likedGame?: Array<string>; // 可选
    
      add(a:number, b:number): number; // 方法
      (a:number, b: number): number; // 可不写函数名
    }
    
    任意属性

    如果我们想要任意属性,用:

    [propName: string] (定义了任意属性取 string 类型的值)

    注意:一旦定义了任意属性,那么确定属性(:)和可选属性(?:)的类型都必须是它的子集(即符合任意属性规则)。

    interface YYY {
      width: number; //因为 propName 的存在,这里只能是 number,如果是其它且不是 number 的子集,会报错
      height: number;
      [propName: string]: number;
    }
    
    let a: YYY = {
        width: 1,
        height: 2,
        age: 23, // 可以额外的属性
        color: "red", // 不行,会报错
    }
    
    获取接口中的某个类型

    用方括号

    interface YYY {
        abc: number
    }
    let b: YYY["abc"] = 1 // 可以这么写,b 的类型是 number, 不能写成 YYY.abc 的形式
    

    继承

    使用 extends 关键字,interface 还可以同时继承多个!

    用 extends
    注意,interface 还可以继承多个!

    interface Animal {
      move(): voil;
    }
    
    interface Organic {
      c: boolean;
      o: boolean;
      h: boolean;
    }
    
    
    interface Human extends Animal, Organic {
      name: string;
      age: number
    }
    
    //必须满足 Human / Organic / Animal 三个接口
    let man: Human = {
      age: 18,
      name: 'kala',
      move(){
        console.log(1,2,3,4)
      },
      c: true,
      o: true,
      h: true
    }
    

    也可以采用另外一种方式继承,一个接一个继承。
    注意,如果两个接口拥有同样的属性描述,那么没办法一同被继承,也不能一个继承另一个,除非两个类型描述是一样的。


    类 class

    类的定义与接口类似,就是用来告诉你一个对象必须有什么属性

    接口是低配版的类
    类是高配版的接口

    类的基本特点:
    1.有 constructor,让class 变得非常灵活
    2.类的属性:static
    3.对象的属性:除了 static
    4.继承要用 super

    class Human {
      static xxx = 1 // static (静态属性)的意思是,这个是 Human 的属性,不是实例的属性, 我们没办法直接通过 Human.xxx 来定义
      name: string
      age: number
      constructor(name = "kala", age = 15) { //设置默认值
        this.name = name
        this.age = age
      }
      move(): void {
    
      }
    }
    
    //使用:
    //可以这么用:
    let a = new Human("a", 1)
    
    //还可以当做接口使用
    let b: Human = {
        name: "a",
        age: 1,
        move(){} // 注意,这里要手动写 …… 不过后面也会提到,作为接口、与作为类,对于方法的处理上有着本质的区别
    }
    
    
    类的继承

    注意要在 constructor 中使用 super, 相当于调用了父类的 constructor,是否传参取决于父类 constructor 是否需要参数。

    class A {
      constructor()  {
        console.log('ok')
      }
    }
    
    class B extends A {
      constructor(){
        super() 
      }
    }
    
    修饰符

    1.public : 公开属性
    2.private : 私有属性,升级版的局部作用域;只能在当前 class 中用,不能在子类中使用;
    3.protected : 保护,既不是完全公开,也不是完全不公开,即‘有限公开’; 可以再当前 class 或者子类 class 中使用
    4.get / set
    5.static (静态属性)的意思是,这个是 Human 的属性,不是实例的属性, 我们没办法直接通过 Human.xxx 来定义

    private
    以前,我们通过加一个下划线来让别人知道,这个东西不是给别人用的'_secret', 在 typescript 中很简单,只要在属性名前面加上 private,不过,我们依然会写成 _secret 的形式;

    //私有属性
    class Human {
      static xxx = 1
      name: string
      private _secret: string  // 私有属性,别人用不了
      private _age: number
      get age(){
          return this._age
      }
      set age(value: number){
          if(value < 0) {
              this._age = 0
          } else {
              this._age = value
          }
      }
    
      constructor(name = "kala", age = 15) {
        this.name = name
        this.age = age
      }
    }
    
    //以上的设计,我们没法直接访问 `_age`,因为是 private 的,但是我们又可以通过 age 去设置它,因为 age 的环境是class 内部 ……
    
    static 与 private 的区别

    static 静态属性,被static修饰的变量和方法类似于全局变量和全局方法,可以在不创建对象时调用,当然也可以在创建对象之后调用。
    private 私有属性,对于用户来说,是不可见且不可访问的

    抽象类 (abstract)

    可以叫 “爸爸类”:专门当别的类的爸爸的类

    也可以叫做 “没有写完的类”:只描述有什么方法,并没有完全实现这些方法
    由于这个类没有写完,所以不能创建出对象。

    interface 不能写函数的实现,直接是 xxx(): void
    class 可以要函数的实现 :xxx(): void { ... }
    abstract 就是把 class 中的函数‘降级’到原来的写法 abstract xxx(): void

    也就是说:

    interface: 知道有这么个方法
    class: 知道一个具体的方法
    abstract: 知道有这个方法,并且后续的之类需要把这个方法具体化

    举个例子,Animal 有个 calls (叫声)的函数,但是我们不确定每个动物具体怎么叫,于是我们就可以在 Animal 中写 abstract calls(): void

    也就是,如果类中的一个方法不好写实现,就在前面加个 abstract,

    abstract 小结:
    1.如果一个类的某个函数是抽象函数,那么我们要在这个类的前面也加上一个 abstract,比如 abstract Animal
    2.这个类不能用来创建对象;
    3.子类继承这个抽象类之后,要把这儿抽象函数完善。


    类型断言(类型转换)

    为了防止 ts 报错,主动告诉编译器,我知道这个东西的类型是什么
    1.使用尖括号
    2.使用 as 关键字

    (<string>a).split('') // 意思是说,我知道 a 类型是 string
    (a as string).split('') // 等同于上面那一句
    

    注意,当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。

    语法 & 关键字

    Partial
    Partial<XXX> // 得到的属性与 XXX 里面的属性一样,不过都是可选 :?
    
    type

    alias 别名
    type Layout = React.FuncionComponent & { Header: React.FunctionComponent }

    keyof

    关键字: keyof 代表一个类型的 key (用 | 连起来), 比如 keyof Person

    keyof Person // 就相当于 'age' | 'name' | 'sex'

    注意,这里的 extends 与平时看到的 extends 不是同一个意思

    in

    in 与 extends 的区别:
    extends 是 |
    in 是 &

    K in keyof Person
    
    中括号 [ ]
    A[] // 意思是 A 组成的数组;
    A["name"] // 意思是 A 类型里面的 "name" 属性的类型
    

    &

    且运算,一定要同时满足多个

    |

    或运算,可以满足一个或者多个

    Readonly

    Readonly VS readonly
    Readonly<XXX> // 得到的属性与 XXX 里面的属性一样,不过都是只读的 readonly。

    declare(未学习)

    import & require
    import XXX from './xxx.js'  // xxx 的类型是 any
    const XXX: string = require('./xxx.js') // 这个可以写类型
    

    如果想要让 import 也有类型,需要创建一个同名的 .d.ts 文件:

    declare function y(a: number, ba; number): number;
    export default y
    

    这样,上面的引入的东西,类型就不是 any 了

    其它

    类型兼容
    interface Human {
        name: string;
        age: number;
    }
    
    let x: Human = {name: 'abc', age: 18, gender: 'male'} // 报错
    
    let y = {name: 'abc', age: 18, gender: 'male'};
    let x: Human = y; // 通过另外一个对象赋值过来,不会报错 …… 
    

    好处是,你可以少声明一些类型,不用特别声明一个 ……

    soundness

    我们在用函数的时候,有时会出现 类型不一致但是可以通过的想象,因为我给你的类型更加具体。

    用 ts 添加 window 变量
    declare global {
        interface Window {
            server: {  // window.server
                host: string
            }
        }
    }
    
    给 React 添加全局属性
    declare module 'react' {
        const xxx: number;
        //一般我们也改不了 React 全局属性,不过可以在这里改:比如改(拓展) HTMLAttributes
        interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {
            styleName ?: string // 在原来的基础上,添加这么一个
        }
    }
    

    相关文章

      网友评论

          本文标题:typescript基本类型与语法

          本文链接:https://www.haomeiwen.com/subject/cbknyctx.html