zhangzheng-zz / blog

1 stars 0 forks source link

Typescript学习 #3

Open zhangzheng-zz opened 4 years ago

zhangzheng-zz commented 4 years ago

为什么使用Typescript?

let name: Name; name = { first: 'John', second: 'Doe' };

name = { // Error: 'Second is missing' first: 'John' };

name = { // Error: 'Second is the wrong type' first: 'John', second: 1337 };

### 内联类型注解
如果不想使用接口定义一个对象类型,可以直接使用内联定义的写法
```js
let name: {
  first: string;
  second: string;
};

name = {
  first: 'John',
  second: 'Doe'
};

特殊类型

// 赋值任意类型 power = '123'; power = 123;

// 它也兼容任何类型 let num: number; power = num; num = power;

- **null 和 undefined**  null 和 undefined 字面量可赋值给任意类型的变量
- **void** 表示函数无返回值
```js
function log(message: string): void {
  console.log(message);
}

联合类型

变量 a 可以为 number 或者是 string 类型

let a: number | string

交叉类型

从两个对象中创建一个新对象,新对象拥有着两个对象所有的功能

// 参数 first 和 second 分别为 T 和 U 两个泛型 
// 返回结果为 T 和 U 的交叉类型

function extend <T, U> (first: T, second: U) : T & U {
  const res = <T & U> {}

  for (let id in first) {
     (<T>res)[id] = first[id]
  }

  for (let id in second) {
     if (!result.hasOwnProperty(id)) {
       (<U>result)[id] = second[id];
     }
   }

 return res
}

const x = extend({ a: 'hello' }, { b: 42 });

// 现在 x 拥有了 a 属性与 b 属性
const a = x.a;
const b = x.b;

元组

类似js中的数组,可以指定各种类型[typeofmember1, typeofmember2, ......]

 let nameNumber: [string, number];

// Ok
nameNumber = ['Jenny', 221345];

// Error
nameNumber = ['Jenny', '221345'];

字面量类型

你可以使用一个字符串字面量作为一个类型:

let foo: 'Hello';

可以在一个联合类型中组合创建一个强大的(实用的)抽象:

type CardinalDirection = 'North' | 'East' | 'South' | 'West';

function move(distance: number, direction: CardinalDirection) {
  // ...
}
move(1, 'North'); // ok
move(1, 'Nurth'); // Error

泛型

设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:

2. 泛型

使用泛型

创建一个函数,使得返回值的类型与传入参数的类型是相同

function identity<T>(arg: T): T {
    return arg;
}

使用泛型变量

把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性。

function loggingIdentity<T>(arg: T[]): T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

也可以这样写

function loggingIdentity<T>(arg: Array<T>): Array<T> {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

泛型函数loggingIdentity,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素类型是T的数组。

泛型类型

泛型函数的类型与非泛型函数的类型没什么不同,只是有一个类型参数在最前面,像函数声明一样:

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;

使用对象字面量来定义泛型函数

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;

使用泛型接口

interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

我们可能想把泛型参数当作整个接口的一个参数

interface GenericIdentityFn<T> {
    (arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

使用 GenericIdentityFn的时候,还得传入一个类型参数来指定泛型类型(这里是:number),锁定了之后代码里使用的类型。

泛型类

泛型类使用( <>)括起泛型类型,跟在类名后面

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

泛型约束

我们想限制函数去处理任意带有 .length 属性的所有类型,只要传入的类型有这个属性就允许,为此需要列出对 T 的约束 定义一个接口来描述约束条件, 创建一个包含 .length 属性的接口,使用这个接口和extends关键字来实现约束

interface Lengthwise {
    length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

3. 如何编写 d.ts 文件

d.tsts中的声明文件,编写声明文件的好处是可以帮助我们在写代码的时候能够看到编辑器的提示

常用的前端库的声明文件(d.ts)可以在DefinitelyTyped中找到通过 npm i @types/xxx安装

全局类型

变量

declare var aaa:number

关键字declare表示声明的意思。在d.ts文件里面,在最外层声明变量、函数或者类要在前面加上这个关键字。在typescript的规则里面,如果一个.ts、.d.ts文件如果没有用到import或者export语法的话,那么最顶层声明的变量就是全局变量。

函数

decalre function getName(id:number|string):string

同一个函数有若干种写法:

get(1234)
get("zhangsan",18)

d.ts对应的写法:

declare function get(id: string | number): string
declare function get(name:string,age:number): string

class

declare class Person {

    static maxAge: number //静态变量
    static getMaxAge(): number //静态方法

    constructor(name: string, age: number)  //构造函数
    getName(id: number): string 
}

对象

namespace声明对象

declare namespace OOO{

}

当然了这个对象上面可能有变量,可能有函数可能有类。

declare namespace OOO{
    var aaa: number | string
    function getName(id: number | string): string
    class Person {

        static maxAge: number //静态变量
        static getMaxAge(): number //静态方法

        constructor(name: string, age: number) //构造函数
        getName(id: number): string //实例方法
    }
}

对象里面套对象也是可以的:

declare namespace OOO{
    var aaa: number | string
    // ...
    namespace O2{
        let b:number
    }
}

混合类型

既是函数又是对象


declare function $2(s:string): void

declare namespace $2{
    let aaa:number
}

既是函数,又是类(可以new出来)

// 1、实例方法 
interface People{
    name: string
    age: number
    getName(): string
    getAge():number
}
interface People_Static{
    // 2、构造函数 
    new (name: string, age: number): People
    new (id:number): People

    // 3、作为类,调用类上的方法或者变量 
    staticA():number
    aaa:string

    // 4、作为函数使用 
    (w:number):number
    (w:string):number
}
declare var People:People_Static

console.log(a1) console.log(a2)

对应的 A.d.ts 文件(推荐)
```js
declare var a1: 1
declare var a2: 2
export { a1,a2 }

也可以写成这样

export declare var a1: 1
export declare var a2: 2

default的默认导出

declare var a1: 1
export default a1

使用

import a1 from "./A";
console.log(a1)

模块化下的全局变量

有时候我们定义全局变量的时候需要引入(别人写的)文件,比如这样的,我想声明个全局变量req:

import { Request } from 'express'
declare var req: Request 

由于我们当前的d.ts文件使用了import/export语法,那么ts编译器就不把我们通过declare var xxx:yyy当成了全局变量了,那么我们就需要通过以下的方式声明全局变量:

import { Request,Response} from 'express'
declare global {
    var req: Request
}

UMD

有一种代码,既可以通过全局变量访问到,也可以通过require的方式访问到。比如我们最常见的jquery

$.ajax()
let j = require('jquery')
j.ajax()

按照全局的方式写d.ts,写完后在最后加上declare module "xxx"的描述:

declare namespace UUU{
    let a:number
}

declare module "UUU" {
    export =UUU
}

内置对象的扩展

有时候我们扩展了一些内置对象。比如我们给Date增加了一个format的实例方法:

interface Date {
    format(f: string): string
}

参考:

https://jkchao.github.io/typescript-book-chinese/ https://segmentfault.com/a/1190000009247663 https://www.tslang.cn/docs/handbook/generics.html