{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'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 Foo {};
interface Bar {};
type Bas = {};
class Foo {}
const someVar = Foo;
const someOthervar = 123;
//文件定义在foo.js文件中
export const foo = 123;
//文件定义在一个文件中
import { foo } from './foo';
const bar = foo;
首先需要明白关于这些模块系统的不一致性。需要根据不同的module选项来把TypeScript编译成不同的js模块类型。
如何书写TypeScript模块
ES5模块语法
export const someVar = 123;
export type someType = {
foo: stringl
}
const someVar = 123;
type someType = {
type: string;
}
export { someVar someType }
const someVar = 123;
export { someVar as aDifferentName };
import { someVar, someType } from './foo';
import { someVar as aDifferentName } from './foo';
import * as foo from './foo';
//此时可以使用'foo.someVar'和‘foo.someType’以及其他任何从‘foo'到处的变量或者类型
import 'core-js';
export * from './foo';
export { someVar } from './foo';
export { someVar as aDifferentName } from './foo';
默认导入/导出
模块路径,存在两种截然不同的模块:
相对模块路径
动态查找,当导入路径不是相对路径时,模块解析将会模仿Node模块解析器,如:
重写类型的动态查找
declare module 'foo' {
export var bar: number;
}
import * as foo from 'foo';
import/require仅仅是导入类型,如下所示
import foo = require('foo');
import foo = require('foo');
let bar: foo.someType;
import foo = require('foo');
export function loadFoo() {
//懒加载foo,原始的加载仅仅用来做类型注解
const _foo: tyoeof foo = require('foo');
}
import foo = require('foo');
export function loadFoo() {
require(['foo'], (_foo: typeof foo) => {
//使用'_foo'替代'foo'来作为变量使用
})
}
import foo = require('./foo');
import bar = require('./bar');
import bas = require('./bas');
const ensureImport: any = foo || bar || bas
(function(something) {
smoething.foo = 123;
})(something || (something = {} ))
let something;
(function(something) {
something.foo = 123;
})(something || (something = {}));
console.log(something);
// { foo: 123 }
(function(something) {
something.bar = 456;
})(something || (something = {}));
console.log(something); // { foo: 123, bar: 456 }
namespace Utility {
export function log(msg) {
console.log(msg);
}
export function error(msg) {
console.log(msg);
}
}
//usage
Utility.log('Call me');
Utility.log('maybe');
(function(Utility){
//....
})(Utility || (Utility = {}))
//webpack加载方式
import(/* webpackChunkName: "momentjs" */ 'moment')
.then(moment => {
//懒加载的模块拥有所有类型,并且能按期工作
//类型检查会工作,代码引用也会工作 :100:
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))
//tsconfig.json配置文件
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"lib": [
"dom",
"es5",
"scripthost",
"es2015.promise"
],
"jsx": "react",
"declaration": false,
"sourceMap": true,
"outDir": "./dist/js",
"strict": true,
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types"
],
"types": [
"node",
"react",
"react-dom"
]
}
}
declare module 'jquery';
import * as $ from 'jquery';
declare module '*.css';
// 声明之后可以使用import * as foo from './some/file.css'
npm install @types/jquery
import * as $ from 'jquery';
{
"compilerOptions": {
"types": [
"jquery"
]
}
}
foo = 123;
declare var foo: any;
foo = 123;
你可以选择把这些声明放在.ts或者.d.ts里,在实际项目里,强烈建议你应该把声明放在独立的.d.ts里。如果一个文件有扩展名.d.ts,这意味着每个根级别的声明都必须以declare关键字作为前缀。这有利于让开发者清楚知道,
在这里ts将不会把它编译成任何代码,同时开发者需要确保这些在编译时存在
变量,当想告诉ts编译器关于process变量时,可以采用下面的这种方式
declare let process: any';
//允许你使用process,并能成功通过typescript的编译:
process.exit();
//推荐尽可能的使用接口,例如:
interface Process {
exit(code?: number): void;
}
declare let process: Process;
interface Point {
x: number;
y: number;
}
interface Point {
x: number;
y: number;
}
class Point implements Point {
x: number;
y: number;
}
interface Crazy {
new(): {
hello: number;
}
}
class CrazyClass implements Crazy {
constructor() {
return {
hello: 123
}
}
}
enum CardSuit {
Clubs,
Diamonds,
Hearts,
Spades
}
数字类型枚举和数字类型。数字类型枚举,允许将数字类型或者其他任何与数字类型兼容的类型赋值给枚举类型的实例
数字类型枚举与字符串类型,从下面的例子中看出,你可以使用Tristate变量来把字符串枚举类型改造成一个数字或者是数字类型的枚举类型
enum Tristate {
False,
True,
Unkown
}
//被编译成js代码后
var Tristate;
(function(Tristate){
Tristate[(Tristate['False'] = 0)] = 'False';
Tristate[(Tristate['True'] = 1)] = 'True';
Tristate[(Tristate['Unkonw'] = 2)] = 'Unkonw';
})(Tristate || (Tristate = {}));
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1,
EatsFish = 1 << 2,
Endangered = 1 << 3,
}
//在这里使用左移符号,将数字1的二进制向左移动位置得到数字0001,0010,0100, 1000
export enum EvidenceTypeEnum {
UNKNOWN = '',
PASSPORT_VISA = 'passport_visa',
PASSPORT = 'passport',
SIGHTED_STUDENT_CARD = 'sighted_tertiary_edu_id',
SIGHTED_KEYPASS_CARD = 'sighted_keypass_card',
SIGHTED_PROOF_OF_AGE_CARD = 'sighted_proof_of_age_card'
}
const foo = 123;
const bar = foo.toString();
//这段代码的类型检查正常,因为lib.d.ts为所有js对象定义了toString方法,如果在noLi选项下,使用相同的代码,这将会出现类型检查错误
interface Window
extends EventTarget,
WindowTimers,
WindowSessionStorage,
WindowLocalStorage,
WindowConsole,
GlobalEventHandlers,
IDBEnvironment,
WindowBase64 {
animationStartTime: number;
applicationCache: ApplicationCache;
clientInformation: Navigator;
closed: boolean;
crypto: Crypto;
// so on and so forth...
}
interface Window {
helloword(): void;
}
//将允许你以类型安全的形式使用它
window.helloWorld = () => console.log('hello world');
// Call it
window.helloWorld();
// 滥用会导致错误
window.helloWorld('gracius'); // Error: 提供的参数与目标不匹配
tsc --target es5 --lib dom,es6
interface ReturnString {
(): string;
}
//可以表示一个返回值为string的函数:
declare const foo: ReturnString;
const bar = foo();
const simple: (foo: number) => string = foo => foo.toString();
interface CallMeWithNewToGetString {
new (): string;
}
// 使用
declare const Foo: CallMeWithNewToGetString;
const bar = new Foo(); // bar 被推断为 string 类型
function logName(something: { name: string }) {
console.log(something.name);
}
logName({ name: 'matt' }); // ok
logName({ name: 'matt', job: 'being awesome' }); // Error: 对象字面量只能指定已知属性,`job` 属性在这里并不存在。
let: x : { foo : number, [x: string]: any };
x = { foo: 1, baz: 2 }
type Foo = {
kind: 'foo'; // 字面量类型
foo: number;
};
type Bar = {
kind: 'bar'; // 字面量类型
bar: number;
};
function doStuff(arg: Foo | Bar) {
if (arg.kind === 'foo') {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
// 一定是 Bar
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
let foo: 'Hello';
type CardinalDirection = 'North' | 'East' | 'South' | 'West';
type OneToFive = 1 | 2 | 3 | 4 | 5;
type Bools = true | false;
interface Point {
x: number;
y: number;
}
class Point2D {
constructor(public x: number, public y: number) {}
}
let p: Point;
//ok
p = new Point2D(1, 2)
let foo: never = 123; // Error: number 类型不能赋值给 never 类型
// ok, 作为函数返回类型的 never
let bar: never = (() => {
throw new Error('Throw my hands in the air like I just dont care');
})();
interface Square {
kind: 'square';
size: number;
}
interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
if (s.kind === 'square') {
return s.size * s.size;
} else if (s.kind === 'rectangle') {
return s.width * s.height;
}
// 如果你能让 TypeScript 给你一个错误,这是不是很棒?
}
function area(s: Shape) {
switch (s.kind) {
case 'square':
return s.size * s.size;
case 'rectangle':
return s.width * s.height;
case 'circle':
return Math.PI * s.radius ** 2;
default:
const _exhaustiveCheck: never = s;
}
}
const foo: {
[index: string]: { message: string };
} = {};
// 储存的东西必须符合结构
// ok
foo['a'] = { message: 'some message' };
// Error, 必须包含 `message`
foo['a'] = { messages: 'some message' };
// 读取时,也会有类型检查
// ok
foo['a'].message;
// Error: messages 不存在
foo['a'].messages;
// ok
interface Foo {
[key: string]: number;
x: number;
y: number;
}
// Error
interface Bar {
[key: string]: number;
x: number;
y: string; // Error: y 属性必须为 number 类型
}
type Index = 'a' | 'b' | 'c';
type FromIndex = { [k in Index]?: number };
const good: FromIndex = { b: 1, c: 2 };
// Error:
// `{ b: 1, c: 2, d: 3 }` 不能分配给 'FromIndex'
// 对象字面量只能指定已知类型,'d' 不存在 'FromIndex' 类型上
const bad: FromIndex = { b: 1, c: 2, d: 3 };
interface ArrStr {
[key: string]: string | number; // 必须包括所用成员类型
[index: number]: string; // 字符串索引类型的子级
// example
length: number;
}
class Foo {}
const Bar = foo;
let bar: Bar; //error: 不能找到名称'Bar',此时的Bar是一个变量不是类型
let foo = 123;
let bar: typeof foo
class Foo {
foo: number;
}
declare let _foo: Foo;
//与之前做法相同
let bar: typeof _foo.foo;
const colors = {
red: 'red',
blue: 'blue'
}
type Colors = keyof typeof colors;
let color: clors;
try {
throw new Error('Something bad happened');
} catch(e) {
console.log(e);
}