typescript基本类型与语法

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 //数字组成的数组
list3: number[] // 等价于上面

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


ArrayLike

伪数组的定义(源码):

interface ArrayLike {
    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; // 可选

  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 关键字

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

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

语法 & 关键字

Partial
Partial // 得到的属性与 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 里面的属性一样,不过都是只读的 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 extends AriaAttributes, DOMAttributes {
        styleName ?: string // 在原来的基础上,添加这么一个
    }
}

你可能感兴趣的:(typescript基本类型与语法)