TypeScript Basic

最近的一个公司项目中,我给项目加上了TypeScript。 目前项目有三名前端,2019年将会增加更多的前端,更多的项目。 一方面我们使用ESLint控制代码风格,但是我觉得ESLint越来越不够了。所以明年所有前端项目,我都将要求使用TypeScript。

Use types in TypeScript

````ecmascript 6 const myVar: string = ‘hello’; type myObjectType = { a: string; b: number; } class MyClass { myProp: string; /* … */ }


## 标准类型
TypeScript定义了和JavaScript一样的标准类型,同时新增额 `enum`, `any`, `never` 三种新的标准类型。

* `never`: 表示该类型的值永远不会产生,它是永不返回的函数的返回值。它是与 `any`完全相反的一个值。
* `any`: 表示变量可能包含任何值,就像JavaScript的默认行为一样。
* `string`:
* `array`:
* `boolean`:
* `enum`:  
	````typescript
	enum Color {Red, Green, Blue} 
	let c: Color = Color.Green; // (在JS中 c 是一个int类型的值)
    ````
* `null`
* `undefined`

## 富类型

### `Interface`

描述一个用户对象
````typescript
    interface User {
        name: string;
        birthday?: string; // optional property
    }

描述一个函数

    interface MyAddFunction {
        (a: number, b: number): number
    }
    const add: MyAddFunction = (a, b) => a + b;

描述一个 Cat type 重用 Animal type

    interface Animal {
        name: string;
    }
    interface Cat extends Animal {
        mustache_len: number;
    }
    // ---------------------
    interface A { a: string; }
    interface A { b: string; }
    // is the same as 
    interface A {
        a: string;
        b: string;
    }

type

type关键字用于创建 类型别名:

重命名一个现有类型

type MyString = string;

在用于编写doc时很有用

联合类型,扩充

type PossibleValues = "open" | "close";
const a: PossibleValues = "open";
interface Car {
speed: string;
}
type CompetitionCar = Car & { competitor_id: string };

type与interface的区别

以下用法中,两者没有区别

interface A {
a: string;
}
type B = { a: string; }

函数的类型,参数,返回值类型

// inline typing
const capitalize = (str: string): string => {
    return str.charAt(0).toUpperCase() + str.slice(1);
}
// types with interfaces
interface CapitalizeFunction {
    (str: string) => string;
}
const capitalize: CapitalizeFunction = str => {
    return str.charAt(0).toUpperCase() + str.slice(1);
}
// function as property in object
interface ReactComponentProps {
    onClick: (e: React.MouseEvent<HTMLDivElement>) => void;
}
class MyComponent extends React.Component<ReactComponentProps> { }

对象作为参数

interface MyFunctionArgs {
    name: string;
    security_code: string;
    id?: number;
}
function isCompleteUser({ name, id = 1 }: MyFunctionArgs): boolean {
    return !!name;
}
isCompleteUser({ name: 'a', security_code: 'b' });

泛型

基本类型和Interface可以很好的描述数据和基本函数签名,泛型可以使类型‘开放’和可以重用。 想象我们需要一个这样的方法

function withUID (obj) { 
    return Object.assign({}, obj, { uuid: _.uniqueId() });
}

要给函数加上类型,最直观的方式是

function withUID (obj: any) { 
    return Object.assign({}, obj, { uuid: _.uniqueId() });
}

我们使用 any 是因为我们接受任何类型的对象。

问题是类型推断会推测函数返回的类型也是 any

泛型就是可以使组件能够接收多种类型,更灵活。

function withUID<T>(obj: T) { 
    return Object.assign({}, obj, { uuid: _.uniqueId() });
}

泛型可以应用到 interfaces classfunction

interface A<T, S> {
    a: T;
    b: S;
    c: { id: string } & S;
}

泛型可以  “extends”

function withUID<T extends object>(obj: T) { 
    return Object.assign({}, obj, { uuid: _.uniqueId() });
}
withUID({ a: 1 }); // is valid
withUID("hello"); // is NOT valid

这里 T 应该满足的条件“是对象类型”

interface Person { name: string; }
function withUID<T extends Person>(obj: T) { 
    return Object.assign({}, obj, { uuid: _.uniqueId() });
}
withUID({ name: "POLY", surname: "Chack" }); // is valid

泛型可以有默认类型

interface A<T=string> {
    name: T;
}
const a:A = { name: "Charly" };
const a:A<number> = { name: 101 };

参数的类型可以被其他参数重用

function MyFunction<T extends Person, S=T&{ ssid: string }>(
person: S
): S {
/* ... */
}

重载 可扩展的函数类型

当函数更复杂时,重载就更有用了,想象有这样一个函数 ```ecmascript 6 function getArray(…args) { if (args.length === 1 && typeof args[0] === ‘number’) { return new Array(args[0]) } else if (args.length > 1) { return Array.from(args); } } getArray(5) // => [undefined x 5] getArray(‘a’, ‘b’, ‘c’) // => [‘a’, ‘b’, ‘c’]


如何定义函数的类型呢。最简单的方法就是重载 `overload`

[<img src="/images/overload.jpg" alt="矩阵1"/>](/)


注意: 重载没有函数体。

## super type

联合类型
```typescript
interface BaseConfig { version: string; name: string; }
interface DynamicConfig { fromFile: string; }
interface StaticConfig { configuration: object; }
type Configuration = (StaticConfig | DynamicConfig) & BaseConfig;

现在 Configuration 可以有两个不同的形状

const config: Configuration = {
    version: '1.0',
    name: 'myDynamicConfig',
    fromFile: './config.json'
}; // this is a DynamicConfig
const config: Configuration = {
    version: '1.0',
    name: 'myStaticConfig',
    configuration: { ... }
} // this is a StaticConfig

Written on December 13, 2018