JavaScript · 开发相关

TypeScript Learning

TypeScript 是 JavaScript 类型的超集,它可以编译成纯 JavaScript。

typescript-learning

install

npm

npm install -g typescript

Visual Studio Code

https://www.typescriptlang.org/#download-links

编译

TypeScript 文件后缀名为.ts, 需编译为 .js 文件。

tsc <filename>

config

项目根目录生成 tsconfig.json

{
    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react"
    },
    "include": [
        "./src/**/*"
    ]
}

webpack

npm install -g webpack

npm install --save-dev typescript awesome-typescript-loader source-map-loader

awesome-typescript-loader 可使用 ts-loader 替换。

webpack.config.js

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist"
    },

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx", ".js", ".json"]
    },

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
        ]
    },

    // When importing a module whose path matches one of the following, just
    // assume a corresponding global variable exists and use that instead.
    // This is important because it allows us to avoid bundling all of our
    // dependencies, which allows browsers to cache those libraries between builds.
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    },
};

语言

变量类型

Boolean

let isDone:boolean = false; 

Number

支持 二进制、八进制、十进制、十六进制的浮点数

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

String

支持 "' 包裹字符串。

let color: string = "blue";
color = 'red';

同样支持末模板符串,嵌入表达式${ expr }

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ fullName }. I'll be ${ age + 1 } years old next month.`;

Array

使用 elemType[] 申明:

let list: number[] = [1, 2, 3];

使用 Array<elemType> 申明:

let list: Array<number> = [1, 2, 3];

Tuple

表示不同类型但位置固定的数组


let x: [string, number];

x = ["hello", 10]; // OK
x = [, 10] // OK
x = [10, "hello"]; // Error

x[2] = 'hello';  // OK
x[2] = 10; // OK

x[3] = 10; // OK
x[3] = 'hello'; // OK

x[2] = true; // Error
x[1] = 1; // Error

Enum

枚举类型是给一组数值更友好命名的方式,可参考 C# 中的枚举:

enum Color {Red, Green, Blue};
let c: Color = Color.Green;

默认枚举类型第一个值为 0,第二个为 1,逐一递增。编译成 JavaScript为:

var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));

var c = Color.Green;

我们也能设置某个属性的初始值,其余的值上依次递增:

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green; // 2

或则定义全部值:

enum Color {Red = 1, Green = 3, Blue = 4}
let c: Color = Color.Green; // 2

枚举另一个便利的功能是可以从数值取得对应的字符名

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]; // Green

Any

如果想声明一个不确定类型的变量,使用 any 类型的变量,这在引用第三方框架时很有用。

let noSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

Void

如果一个函数没有返回值可使用 void

function nothingWillReturn(): void {
}

给变量声明 void 类型没什么用,因为之后你只能为其赋值为 undefined 或者 null

Null 和 Undefined

TypeScript 中,nullundefined 是两种不同的类型,分别为 nulltypescript,同 void ,给变量声明这两种类型没什么卵用。

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;

默认情况下,nullundefined 是所有其他类型的子类型。这意味着可以将数值之类赋值给 nullundefined 类型的变量。

// 这样也可以
let u: null = undefined;
let n: undefined = null;

当使用 --strictNullChecks 标志时,nullundefined类型的变量只能赋值各自的对应类型。

let u: null = undefined; // error TS2322: Type 'undefined' is not assignable to type 'null'.
let n: undefined = null; // error TS2322: Type 'null' is not assignable to type 'undefined'.

Never

tbd

类型断言

<type>

let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;

as

let someValue: any = 'this is a string';
let strLength: number = (someValue as string).length;

let

建议使用 let 替代 var

Interface

TypeScript 的
TypeScript 只会检测在 Interface 中申明的类型:

interface Person {
    firstName: string,
    lastName: string
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = { firstName: "Jane", lastName: "User" };
document.body.innerHTML = greeter(user);

类型检测并不要求属性以声明循序出现

Optional Properties(可选属性)

接口属性后面增加?符号,表示该类型是可选的。

interface Person {
    firstName?: string;
    lastName? : string;
}

Readonly Properties(只读属性)

接口属性前加 readonly 修饰符表示该属性是只读属性。

interface Point {
    readonly x: number;
    readonly y: number;
}

ReadonlyArray<T> 可声明一个只读类型的数组类型。

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
readonly vs const

区分它们办法是:readonly 用于属性修饰,而 const 用于变量修饰。

Excess Property Checks(多余属性检测)

TypeScsript 中如果传递了 interface 中未定义的属性,会引发错误。

interface Person {
  name: string
};

function getName(person: Person) {
  console.log(person.name);
}

getName({
  name: 'hubery',
  age: 26,
});
// error TS2345: Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'Person'.
// Object literal may only specify known properties, and 'age' does not exist in type 'Person'.

Function Types (函数类型接口)

声明函数的 params 类型以及返回值类型,这样的函数类型接口( function type interface )也叫签名。

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result > -1;
}

为了函数类型能够正确的进行类型检查,参数的名称不需要匹配(可通过函数参宿循序去匹配)。

let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
    let result = src.search(sub);
    return result > -1;
}

如果你不想声明函数的参数类型,TypeScript 也可以通过上下文推断出参数类型,函数表达式返回值的类型也可以如此推断出。

let mySearch: SearchFunc;
mySearch = function(src, sub) {
    let result = src.search(sub);
    return result > -1;
}

Indexable Types

interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

定义了一个索引为 number 的字符串类型数组的索引签名

变量声明

var

let

块级作用域

let 作用域仅在块级作用域内

let 必须先声明再使用。

不可重复声明

const

let vs. const

Destructuring(解构)

数组解构

在函数中穿插使用解构寒素,并约定类型。

function f([first, second]: [number, number]) {
    console.log(first);
    console.log(second);
}
f([1, 2]);
对象解构

Class Types

接口实现

如 C# 与 Java 中常见用法

Class

Inheritance (继承)

extend

public

TypeScript里,成员都默认为 public

private

private修饰的成员不能在声明它的类外访问

protected

protected修饰的成员在派生类中可以访问

readonly

使用 readonly 修饰符使得属性只读,readonly 属性必须在构造函数或声明时被初始化。

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
Parameter properties

参数属性可以方便地让我们在一个地方定义并初始化一个成员。

class Octopus {
    readonly numberOfLegs: number = 8;
    constructor(readonly name: string) {
    }
}

Accessors(存取器)

首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。 其次,只带有 get不带有 set的存取器自动被推断为 readonly。

Static Properties

static 关键词修饰成员属性,直接使用[类名.成员名]访问,静态属性存在于类本身上面而不是类的实例

Abstract Classes

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。

Function

函数类型

定义函数类型

同 JavaScript 可创建匿名函数与具名函数。

我们可以定义函数的返回值类型,但 TypeScript 根据 return 语句可以自动推断出返回值类型。

function add(x: number, y : number): number {
    return x + y;
}

var add2 = function(x: number, y : number): number {
    return x + y;
}

可选参数与默认值

TypeScript 中传递给函数的参数个数必须与函数期望的参数个数一致。

TypeScript 参数旁添加 ? 表示该参数是可选的,并且可选参数必须位于必须参数后面。

function buildName(firstName: string, lastName?: string) {
  // ...
}

TypeScript 中也可给参数赋默认值可实现默认参数,默认参数可出现在必选参数的前面,其类型可以省略。

function buildName(firstName: string = 'test', lastName: string) {
  // ...
}

function buildName(firstName = 'test', lastName: string) {
  // ...
}

剩余参数

如函数接受多个参数,但不能确定参数个数,使用参数数组 ... + 参数名。

function(firseName" string, ...restOfName: string[])  {
    return firstName + '' + restOfName.join(' ');
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

this

箭头函数能保存函数创建时的 this值,而不是调用时的值。

this 箭头函数

重载

同一个函数提供多个函数类型定义来进行函数重载,TypeScript 查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。

泛型

枚举

第一枚举元素初始值为 0,其余枚举元素的值为上一个枚举成员的值递增 1。

  1. 不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加1。但第一个枚举元素是个例外。 如果它没有初始化方法,那么它的初始值为 0
  2. 枚举成员使用常数枚举表达式初始化。 常数枚举表达式是 TypeScript 表达式的子集,它可在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:
    • 数字字面量
    • 引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的) 如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用。
    • 带括号的常数枚举表达式
    • +, -, ~ 一元运算符应用于常数枚举表达式
    • +,-, *, /, %, <<, >>, >>>, &, |, ^二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为 NaN或Infinity,则会在编译阶段报错。
Tagged:

发表评论

电子邮件地址不会被公开。 必填项已用*标注