Typescript有什么冷门但是很好用的特性?
23 个回答
获取一个值的类型
let defaultState = {
foo: 7,
bar: 'hello'
type State = typeof defaultState;
let nextState: State = {
foo: 'seven',
bar: 'world'
// 不能将类型“{ foo: string; bar: string; }”分配给类型“{ foo: number; bar: string; }”。
// 属性“foo”的类型不兼容。
// 不能将类型“string”分配给类型“number”。
获取一个函数的返回值的类型
function getState() {
return {
foo: 7,
bar: 'hello'
type State = ReturnType<typeof getState>;
let nextState: State = {
foo: 'seven',
bar: 'world'
// 不能将类型“{ foo: string; bar: string; }”分配给类型“{ foo: number; bar: string; }”。
// 属性“foo”的类型不兼容。
// 不能将类型“string”分配给类型“number”。
将一个类型中的所有属性都变成可选属性
let defaultState = {
foo: 7,
bar: 'hello'
type PartialState = Partial<typeof defaultState>;
let partialState: PartialState = {
foo: 8
取出一个类型中的部分属性,生成另一个类型
let defaultState = {
foo: 7,
bar: 'hello'
type PickedState = Pick<typeof defaultState, 'foo'>;
let partialState: PickedState = {
foo: 8,
bar: 'world'
// 不能将类型“{ foo: number; bar: string; }”分配给类型“Pick<{ foo: number; bar: string; }, "foo">”。
// 对象文字可以只指定已知属性,并且“bar”不在类型“Pick<{ foo: number; bar: string; }, "foo">”中。
还有一些其他内置工具类型,可以在把鼠标放到 ReturnType 上,按 F12 查看
高级类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
type Partial<T> = {
[P in keyof T]?: T[P];
type Nullable<T> = {
[P in keyof T]: T[P] | null;
type Proxy<T> = {
get(): T;
set(value: T): void;
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
type Record<K extends string, T> = {
[P in K]: T;
type Diff<T extends string, U extends string> =
({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];
type Overlap<T extends string, U extends string> = Diff<T, Diff<T, U>>;
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
type Overwrite<T, U> = Omit<T, Diff<keyof T, Diff<keyof T, keyof U>>> & U;
type Purify<T extends string> = { [P in T]: T; }[T];
type NonNullable<T> = T & {};
type Required<T> = {
[P in Purify<keyof T>]: NonNullable<T[P]>;
};
在 TS 2.8 +
type Omit = Pick<T, Exclude<keyof T, K>>
在 React JSX 语法中 cast 类型
假设我们已经有了这样一个组件:
export default class Column<T> extends React.Component<ColumnProps<T>, React.ComponentState> {}
因为在 JSX 语法中我们没法 cast 一个具体的 type 给 Column,所以我会这样
class MyColumn extends Column<{
userId?: number,
docId?: string,
title?: string,
}> {}
之后用 MyColumn 代替 Column 组件
重载在官方文档里已经有了,现在是如何为一个重载的函数写高阶函数?
假设我们有重载函数 fn:
declare function fn(r: () => string): string;
declare function fn(r: () => number): number;
这个高阶函数可以这样写:
function myFn(r: () => string): string;
function myFn(r: () => number): number;
function myFn(r: (() => string) | (() => number)): string | number {
type R = ReturnType<typeof r> extends string ? string : number
return fn(r as any) as any as R
其实,这里我承认,在 myFn 里取到 R 没有什么意义,直接
return fn(r as any)
就可以了,但手动 cast myFn 的返回类型,人生就变成彩色的了呢!
如何调用静态方法,并且可以灵活地修改类名?
在 JavaScript 里很简单,Foo 可以随时改(在 VS Code 里也很简单,rename symbol 即可)
class Foo {
static bar = 'Oops!'
getBarLength () {
return this.constructor.bar.length
getBarUpperCase () {
return this.constructor.bar.toUpperCase()
但在 TypeScript 里你可以要忍受重复书写 Foo 的类名:
class Foo {
static bar = 'Oops!'
getBarLength () {
return (this.constructor as typeof Foo).bar.length
getBarUpperCase () {
return (<typeof Foo>this.constructor).bar.toUpperCase()
那么小技巧来了:
class Foo {
'constructor': typeof Foo
static bar = "Oops!"
getBarLength () {
return this.constructor as Foo).bar.length
getBarUpperCase () {
return this.constructor.bar.toUpperCase()
感受自由吧
为函数添加静态属性
在 Class 里 static 关键字给予了我们这种能力,在 JavaScript 中,它也不在话下:
function test () {}
test.cache = {}
仅仅用 TS 给 test 加个签名分发给其它人用,也不成问题:
// xx.d.ts
interface Test {
(): void,
cache: object,
declare const test: Test
export default test
But, 怎么在 TS 中给函数加上静态属性?
先来个丑陋的(我不用):
interface Test {
(): void,
cache: object,
const test = (function () { }) as Test
test.cache = {}
或者 IIFE:
interface Test {
(): void,
cache: object,
const test: Test = (function () {
function test() { }
(test as any).cache = {}
return test as Test
export default test
人生苦短,我用 namespace:
function test () {}