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<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 // 在原来的基础上,添加这么一个
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容