TypeScript学习笔记
阅读时间:全文 2105 字,预估用时 11 分钟
创作日期:2019-10-10
下篇文章:Flutter学习4-基础组件
BEGIN
tsconfig.json配置
{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在编译中的库文件
"allowJs": true, // 允许编译 javascript 文件
"checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相应的 '.d.ts' 文件
"sourceMap": true, // 生成相应的 '.map' 文件
"outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
"rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
"noEmit": true, // 不生成输出文件
"importHelpers": true, // 从 tslib 导入辅助工具函数
"isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
"strictNullChecks": true, // 启用严格的 null 检查
"noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误
"alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 包含类型声明的文件列表
"types": [], // 需要包含的类型声明文件名列表
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 为装饰器提供元数据的支持
},
// 指定编译的文件
"files": [
"./some/file.ts"
],
// 包含的文件
"include": [
"./folder"
],
// 排除的文件
"exclude": [
"./folder/**/*.spec.ts",
"./folder/someSubFolder"
]
}
声明空间
- 类型声明空间, 关键词如: class、interface、type.
- 变量声明空间
命名空间
- 原代码:
namespace Utility {
export function log(msg) {
console.log(msg);
}
export function error(msg) {
console.log(msg);
}
}
// usage
Utility.log('Call me');
Utility.error('maybe');
- 转义后代码:
(function (Utility) {
Utility.log = function msg(msg) {
console.log(msg);
}
Utility.error = function msg(msg) {
console.log(msg);
}
})(Utility || Utility = {});
// usage
Utility.log('Call me');
Utility.error('maybe');
类型系统
基本类型注释
- 样句:
const num: number = 123;
- 类型:
number
、string
、boolean
数组类型注释
- 同类型数组:
const numArr: number[] = [1, 2, 3];
等同于const numArr: Array<number> = [1, 2, 3]
- 不同类型数组:
const coor: [string, number]
常见的类型
- Event
- MouseEvent
- HTMLElement
对象类型注释
- 内联方式
let name: {
first: string;
second: string;
};
- 接口方式
interface Name {
first: string;
second: string;
[key: string]: string;
}
let name: Name;
any、void
- any类型让typescript关闭类型检测;
- void用于函数表示没有返回值.
never
当一个函数从不退出和返回或者一直报错, 则可以使用never代替void
null、undefined
null和undefined可以赋值给任何类型
联合类型
如: const coor: string[] | string;
交叉类型
如在函数中传入两个对象, 属性类型不同时, 此时可以使用交叉类型.
function extend<T, U>(first: T, second: U): T & U {
const result = <T & U>{};
for (let id in first) {
(<T>result)[id] = first[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<U>result)[id] = second[id];
}
}
return result;
}
const x = extend({ a: 'hello' }, { b: 42 }); // x值为{ a: 'hello', b: 42 }
类型别名
如:
type Text = string | { text: string };
type Coordinates = [number, number];
type Callback = (data: string) => void;
类型推断
假设存在接口Foo
interface Foo {
bar: number;
bas: string;
}
- 类型推断方式一, 写法会与jsx冲突
var foo = <Foo> {};
foo.var = 123;
foo.bas = 'hello';
- 类型推断方式二
var foo = {} as Foo;
foo.var = 123;
foo.bas = 'hello';
- 对应的强制类型转换
var foo: Foo = {
var: 123,
bar: 'hellow'
};
Error类型
Error
: 基类;RangeError
: 数字范围越界, 如:console.log.apply(console, new Array(1000000000));
;ReferenceError
: 使用未经定义的变量时, 如:console.log(notValidVar);
;SyntaxError
: 语法错误, 如:1***3;
;TypeError
: 类型错误, 如:('1.2').toPrecision(1);
;URIError
: URI应用错误, 如:decodeURI('%');
函数
基本注释
// 参数注解
function foo(par1: string) {}
// 返回类型注解
function foo(par1: string): number {}
// 可选参数
function foo(par1: string, par2?: number): number {}
// 默认值
function foo(par1: string, par2: number = 0): number {}
函数重载
interface Overloaded {
(foo: string): string;
(foo: number): number;
}
// 实现接口的一个例子:
function stringOrNumber(foo: number): number;
function stringOrNumber(foo: string): string;
function stringOrNumber(foo: any): any {
if (typeof foo === 'number') {
return foo * foo;
} else if (typeof foo === 'string') {
return `hello ${foo}`;
}
}
const overloaded: Overloaded = stringOrNumber;
// 使用
const str = overloaded(''); // str 被推断为 'string'
const num = overloaded(123); // num 被推断为 'number'
类
什么类属性的方式有: static
、public
、protected
、private
其中static
表示类对象的属性, 实例化对象及类内部无法引用.
类型 | public | protected | private | static |
---|---|---|---|---|
class | yes | yes | yes | no |
class children | yes | yes | no | no |
class instances | yes | no | no | no |
- public、protected、private的使用示例
class FooBase {
public x: number;
private y: number;
protected z: number;
}
// 类实例化
var foo = new FooBase();
foo.x; // okay
foo.y; // ERROR : private
foo.z; // ERROR : protected
// 类继承
class FooChild extends FooBase {
constructor() {
super();
this.x; // okay
this.y; // ERROR: private
this.z; // okay
}
}
- static的使用示例
// typescript代码, 转换前
class Something {
static instances = 0;
constructor() {
Something.instances++;
}
}
var s1 = new Something();
var s2 = new Something();
console.log(Something.instances); // 2
// ecma5代码, 转换后
var Something = (function () {
function Something() {
Something.instances++;
}
Something.instances = 0;
return Something;
})();
var s1 = new Something();
var s2 = new Something();
console.log(Something.instances); // 2
泛型
- 泛型在类中的使用
class Queue<T> {
private data = [];
push(item: T) { this.data.push(item); }
pop(): T | undefined { return this.data.shift(); }
}
const queue = new Queue<number>();
queue.push(0);
queue.push("1"); // ERROR : cannot push a string. Only numbers allowed
- 在函数中使用
function reverse<T>(items: T[]): T[] {
var toreturn = [];
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items[i]);
}
return toreturn;
}
var sample = [1, 2, 3];
var reversed = reverse(sample);
console.log(reversed); // 3,2,1
reversed[0] = '1'; // Error!
reversed = ['1', '2']; // Error!
reversed[0] = 1; // Okay
reversed = [1, 2]; // Okay
- 一个很好的示例
const getJSON = <T>(config: {
url: string,
headers?: { [key: string]: string },
}): Promise<T> => {
const fetchConfig = ({
method: 'GET',
'Accept': 'application/json',
'Content-Type': 'application/json',
...(config.headers || {})
});
return fetch(config.url, fetchConfig)
.then<T>(response => response.json());
}
type LoadUsersResponse = {
users: {
name: string;
email: string;
}[];
}
function loadUsers() {
return getJSON<LoadUsersResponse>({ url: 'https://example.com/users' });
}
- 泛型用于简单函数
declare function send<T>(arg: T): void;
send<number[]>([1, 2]);
模块
模块的导入导出方式与ES6的差不多, 当导入接口类型应注意如下区别:
// typescript, 转换前
import foo = require('foo');
var bar: foo;
// javascript, 转换后
var bar;
// typescript, 转换前
import foo = require('foo');
var bar = foo;
// javascript, 转换后
var foo = require('foo');
var bar = foo;
模块动态引入
import(/* webpackChunkName: "momentjs" */ "moment")
.then((moment) => {
// lazyModule has all of the proper types, autocomplete works,
// type checking works, code references work \o/
const time = moment().format();
console.log("TypeScript >= 2.4.0 Dynamic Import Expression:");
console.log(time);
})
.catch((err) => {
console.log("Failed to load moment", err);
});
关键字解释
declare
当需要实例化一个变量但又不给它赋值时使用
implement
用于类声明继承接口
interface Point {
x: number; y: number;
}
class MyPoint implements Point {
x: number; y: number; // Same as Point
}
readonly
标记为只读
type Foo = {
readonly bar: number;
readonly bas: number;
}
// Initialization is okay
let foo: Foo = { bar: 123, bas: 456 };
// Mutation is not
foo.bar = 456; // Error: Left-hand side of assignment expression cannot be a constant or a read-only property
typeof
获取变量的类型, 将继承被typeof元素的特性, 当为const时, 赋值不可变, 如:
// typeof的变量是var或者let实例化的
var foo = 123;
var bar: typeof foo; // 此时bar为number类型
bar = 456; // Okay
bar = '789'; // ERROR: Type `string` is not `assignable` to type `number`
// typeof的变量是const实例化的
const foo = 123;
var bar: typeof foo;
bar = 123; // Okay
bar = 789; // ERROR: Type '789' is not assignable to type '123'
keyof
获取键名keyof 对象类型
, 如和typeof配合使用:
const colors = {
red: 'reddish',
blue: 'bluish'
}
type Colors = keyof typeof colors;
// 等效于
type Colors = 'red' | 'blue';
FINISH
下篇文章:Flutter学习4-基础组件