01键
keyof 与 Object.keys 略有相似,只不过 keyof 取的是接口的 key。
interface Point {
x: number;
y: number;
}
// type keys = "x" | "y"
type keys = keyof Point;
假设有一个如下所示的对象,我们需要使用typescript实现一个get函数来获取它的属性值
const data = {
a: 3,
hello: 'world'
}
function get(o: object, name: string) {
return o[name]
}
无法确认返回类型:这会失去ts最大的类型校准功能 难以约束key:可能会出现拼写错误
这时可以使用keyof来加强get函数的类型功能。 有兴趣的朋友可以看一下_.get的type标签和实现
function get(o: T, name: K): T[K] {
return o[name]
}
现在您了解了 keyof,您可以使用它对属性进行一些扩展,例如实现 Partial 和 Pick。 pick通常用在_.pick中
type Partial = {
[P in keyof T]?: T[P];
};
type Pick = {
[P in K]: T[P];
};
interface User {
id: number;
age: number;
name: string;
};
// 相当于: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial
// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick
03条件类型
T extends U ? X : Y
type isTrue = T extends true ? true : false
// 相当于 type t = false
type t = isTrue
// 相当于 type t = false
type t1 = isTrue
thenevertype 表示从未出现过的值的类型。
never 和条件类型结合可以产生许多有趣且实用的类型,例如 Omit
type Exclude = T extends U ? never : T;
// 相当于: type A = 'a'
type A = Exclude
type Omit = Pick<T, Exclude>;
interface User {
id: number;
age: number;
name: string;
};
// 相当于: type PickUser = { age: number; name: string; }
type OmitUser = Omit
05类型
顾名思义typescript 定义map,typeof 表示取某个值的类型。 它们的用法可以通过以下示例进行演示。
const a: number = 3
// 相当于: const b: number = 4
const b: typeof a = 4
在典型的服务器端项目中,我们经常需要往上下文中塞一些工具,比如config、logger、dbmodels、utils等,这时候就用到了typeof。
import logger from './logger'
import utils from './utils'
interface Context extends KoaContect {
logger: typeof logger,
utils: typeof utils
}
app.use((ctx: Context) => {
ctx.logger.info('hello, world')
// 会报错,因为 logger.ts 中没有暴露此方法,可以最大限度的避免拼写错误
ctx.loger.info('hello, world')
})
06是
在此之前,我们先看一下koa的错误处理流程。 下面是集中处理错误的过程,但是标记了代码。
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
let code = 'BAD_REQUEST'
if (err.isAxiosError) {
code = `Axios-${err.code}`
} else if (err instanceof Sequelize.BaseError) {
}
ctx.body = {
code
}
}
})
在err.code处,会出现编译错误,提示Property'code'doesnotexistontype'Error'.ts(2339)。
这时候可以使用asAxiosError或者asany来防止错误,但是强制类型转换不够友好。
if ((err as AxiosError).isAxiosError) {
code = `Axios-${(err as AxiosError).code}`
}
这时候可以使用is来判断值的类型
function isAxiosError (error: any): error is AxiosError {
return error.isAxiosError
}
if (isAxiosError(err)) {
code = `Axios-${err.code}`
}
在GraphQL的源码中,有很多这样的用法来标记类型
export function isType(type: any): type is GraphQLType;
export function isScalarType(type: any): type is GraphQLScalarType;
export function isObjectType(type: any): type is GraphQLObjectType;
export function isInterfaceType(type: any): type is GraphQLInterfaceType;
07接口&类型
接口和类型有什么区别?可以参考以下stackoverflow问题
一般来说typescript 定义map,接口和类型的区别很小,比如下面两种写法就类似
interface A {
a: number;
b: number;
};
type B {
a: number;
b: number;
}
interface A {
a: number;
}
interface A {
b: number;
}
const a: A = {
a: 3,
b: 4
}
08字典&许多
这些句子糖是从lodash的types源代码中学习到的,在日常工作中使用得相当频繁。
interface Dictionary {
[index: string]: T;
};
interface NumericDictionary {
[index: number]: T;
};
const data:Dictionary = {
a: 3,
b: 4
}
与使用字面量对象来维护常量相比,constenum 可以提供更安全的类型检测
// 使用 object 维护常量
const enum TODO_STATUS {
TODO = 'TODO',
DONE = 'DONE',
DOING = 'DOING'
}
// 使用 const enum 伟华常量
const enum TODO_STATUS {
TODO = 'TODO',
DONE = 'DONE',
DOING = 'DOING'
}
function todos (status: TODO_STATUS): Todo[];
todos(TODO_STATUS.TODO)
10VSCodeTips&TypescriptCommand
有时在使用VSCode时,用tsc编译时形成的问题与vscode提示的问题不一致
找到项目右下角Typescript字样,两侧显示其版本号。 你可以点击选择UseWorkspaceVersion,这意味着项目所依赖的typescript版本仍然存在。
或者编辑 .vs-code/settings.json
{
"typescript.tsdk": "node_modules/typescript/lib"
}
11Typescript路线图
最后也是最重要的一点,阅读Roadmap来了解ts的一些新功能和bug修复。
Typescript路线图
参考