tsc指令
首先下载TypeScript。
我选择了npm安装的方式:
npm install typescript --save-dev
通过npx tsc运行TypeScript编译器。
执行tsc指令会编译tsconfig.json定义的最近的一个项目。也可以传递你想要编译的文件名tsc index.ts。需要全局安装Typescript才能直接使用tsc指令,只在某个项目中安装了使用npx tsc。
前面的文章中已经提到过--strictNullChecks,更多的选项可以看tsc指令选项。
TS配置
目前的tsconfig.json文件是这样的:
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"baseUrl": "./",
"jsx": "react",
"paths": {
"@/*": ["src/*"]
},
"moduleResolution": "node",
"esModuleInterop": true,
"experimentalDecorators": true,
"strictNullChecks": true,
"noImplicitThis": true,
},
"include": [
"src/*",
"src/**/*",
"typings/*",
"__tests__/*",
"__tests__/**/*"
]
}
这个配置是在练习的过程中因为遇到一些问题一点点加上来的。
target设置为ES2020,为了识别ES2020语法。
"module": "ES2020", , 处理动态导入模块的时候报错:Dynamic imports are only supported when the '--module' flag is set to 'es2020', 'esnext', 'commonjs', 'amd', 'system', or 'umd'.。
"baseUrl": "./", ,必须设置了baseUrl选项,才能使用paths选项。
"jsx": "react",,jsx用来设置jsx语法是以什么方式转换为JavaScript的。
"paths": { "@/*": ["src/*"] },,因为在Webpack中定义了路径的别名@,在tsconfig.json中也需要做相应的配置。
"moduleResolution": "node",,处理import报错:Cannot find module 'axios' or its corresponding **type** declarations.。
"experimentalDecorators": true,,为了识别装饰器语法。
"strictNullChecks": true,,开启严格的null检查。
完整的tsconfig配置。
部分更新功能
1.可选链
let x = foo?.bar.baz();
等同于:
let x = foo === null || foo === undefined ? undefined : foo.bar.baz();
2.空位合并
let x = foo ?? bar();
等同于:
let x = foo !== null && foo !== undefined ? foo : bar();
3.断言函数
assert(someValue === 42);
如果someValue === 42为假,就会抛出一个AssertionError。
通用类型
TypeScript提供了一系列通用类型促进通用类型转换。这些通用类型是全局可访问的。
Partial<Type>
构造一个类型包含Type的所有属性并且将属性设置为可选的。这个通用方法会返回一个代表给出的类型的所有子集的类型。
interface A {
m1: number;
m2: number;
}
const a: Partial<A> = {
};
给a赋值一个空对象没有报类型错误是因为类型Partial<A>将类型A的m1、m2属性都变成可选的了。
Readonly<Type>
构造一个包含Type的所有属性的类型,属性被设置为只读,意味着构造类型的属性不能被重新赋值。
interface A {
m1: number;
m2: number;
}
const a1: Readonly<A> = {
m1: 1,
m2: 2,
}
a1.m1 = 123; // 报错:Cannot assign to 'm1' because it is a read-only property.
给m1属性赋值会报错,因为类型Readonly<A>将类型A的属性都变为只读的了。
Record<Keys,Type>
构造了一个包含类型Type的属性Keys的集合。这个通用函数能被使用来匹配一个类型的属性到另一个类型。
interface A1 {
a1: number;
}
type Keys = 'm1' | 'm2';
const a2: Record<Keys, A1> = {
m1: { a1: 1 },
m2: { a1: 1 },
}
Keys是对象的属性名的类型,A1是对象的属性值的类型。
Pick<Type, Keys>
通过从类型中挑选出属性Keys的集合构造一个类型。将类型Type中的部分属性拿出来作为一个新的类型。
interface A2 {
m1: number;
m2: string;
m3: string;
}
const a3: Pick<A2, 'm1' | 'm2'> = {
m1: 1,
m2: '2',
}
Pick<A2, 'm1' | 'm2'>类型从类型A2中拿出了m1和m2属性组成一个新的类型。
Omit<Type, Keys>
构造一个从Type中挑选出了所有属性的类型,然后移除Keys。将类型Type中的部分属性剔除掉,剩下的属性作为一个新的类型。
interface A2 {
m1: number;
m2: string;
m3: string;
}
const a4: Omit<A2, 'm1' | 'm2'> = {
m3: 'string',
}
Omit<A2, 'm1' | 'm2'>类型从类型A2中剔除了m1和m2属性,剩下的属性组成一个新的类型。
Exclude<Type, ExcludedUnion>
通过从Type中排除所有可以赋值给ExcludedUnion的联合成员来构造一个类型。
type A3 = Exclude<'m1' | 'm2' | 'm3', 'm1'>;
let a5: A3 = 'm2';
a5 = 'm3';
现在 Exclude<'m1' | 'm2' | 'm3', 'm1'>类型相当于类型'm2'|'m3'。在'm1' | 'm2' | 'm3'类型中,能赋值给'm1'的类型是'm1',把这个类型排除,剩下的就是类型'm2'|'m3'。
Extract<Type, Union>
通过从Type中取出所有可以赋值给Union的联合成员来构造一个类型。
type A4 = Extract<'m1' | 'm2' | 'm3', 'm1'>;
const a6: A4 = 'm1';
类型'm1' | 'm2' | 'm3'中,能赋给字面量类型'm1'的只有m1,所以A4的类型就是'm1'。
NonNullable<Type>
构造一个从Type中移除了null和undefined的类型。
type T5 = NonNullable<undefined | null | number>;
let a7: T5 = 1;
a7 = undefined; // 报错:Type 'undefined' is not assignable to type 'number'.
Parameters<Type>
从一个函数类型Type的参数使用的类型构造一个元组类型。
type T6 = Parameters<(x: number, y: number) => number>;
const a8: T6 = [1, 2];
T6的类型相当于[x: number, y: number]。
ConstructorParameters<Type>
从构造函数的类型中构造一个元组或者数组类型。这会是一个元组类型包含所有的参数类型(或者never类型如果Type不是一个函数的话)。
interface A5 {
new (x: number, y: string): number;
}
type T7 = ConstructorParameters<A5>;
const a9: T7 = [1, '2'];
T7的类型是[x: number, y: string]。
ReturnType<Type>
构造一个由类型为Type的函数类型的返回类型组成的类型。
type T8 = ReturnType<() => number>;
const a10: T8 = 123;
ReturnType<() => number>的类型就是number。
InstanceType<Type>
构造出一个类型为Type的构造函数的实例的类型。
class ClassA {
m1: number;
constructor (x) {
this.m1 = x;
}
m2 (y: number) {
return y;
}
}
type T9 = InstanceType<typeof ClassA>;
const a11: T9 = {
m1: 1,
m2: (y) => {
return y;
},
}
Required<Type>
造一个类型组合,所有Type的属性都被设置为必须。和Partial相反。
interface A5 {
m1?: number;
m2?: string;
}
type T10 = Required<A5>;
const a12: T10 = {
m1: 1,
m2: '2'
}
ThisParameterType<Type>
取出一个函数类型的this参数的类型,或者是unknown如果函数类型没有this参数的话。
interface A6 {
(this: number, x: string, y: number): void;
}
type T11 = ThisParameterType<A6>;
const a13: T11 = 1;
T11的类型就是this参数的类型,在这个例子中是number。
OmitThisParameter<Type>
从Type中移除掉this参数。如果Type没有明确地声明this参数,结果就是简单的Type,否则,一个新的没有this参数的函数类型会从Type被创建。泛型被去掉了,并且只有最后一个重载标志能传递到新的函数类型中。
interface A6 {
(this: number, x: string, y: number): void;
}
type T12 = OmitThisParameter<A6>;
const a14: T12 = function (x: string, y: number) {
console.log('a');
}
T12的类型是类型A6移除掉this参数的类型,即(x: string, y: number) => void。
ThisType<Type>
这个通用方法不返回一个转化后的类型。相反地它作为一个上下文this类型的标记来处理。注意 --noImplicitThis标志必须能够在这个通用方法中被使用。
比如官网的这个例子中,使用ThisType<D & M>标明在methods中,this的类型是D&M。
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {};
let methods: object = desc.methods || {};
return { ...data, ...methods } as D & M;
}
let obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx; // Strongly typed this
this.y += dy; // Strongly typed this
},
},
});
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
| TypeScript学习笔记 | |
|---|---|
| 《TypeScript学习笔记-1-基础类型、字面量类型、类型声明》 | |
| 《TypeScript学习笔记-2-联合类型&交叉类型、泛型、类型守卫、类型推断》 | |
| 《TypeScript学习笔记-3-枚举、函数、类、装饰器》 | |
| 《TypeScript学习笔记-4-模块、命名空间》 | |
| 当前篇 | 《TypeScript学习笔记-5-tsc指令、TS配置、部分更新功能、通用类型》 |