www.typescriptlang.org/docs/handbo…
// infer 的中文是“推断”的意思,一般是搭配上面的泛型条件语句使用的,所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。举个例子
type Foo<T> = T extends { t: infer Test } ? Test : string;
// infer 的中文是“推断”的意思,一般是搭配上面的泛型条件语句使用的,所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。举个例子
// infer用来对满足的泛型类型进行子类型的抽取
type One = Foo<number>; // string,因为number不是一个包含t的对象类型
type Two = Foo<{ t: boolean }>; // boolean,因为泛型参数匹配上了,使用了infer对应的type
type Three = Foo<{ a: number; t: () => void }>; // () => void,泛型定义是参数的子集,同样适配
type Obj = { name: string; age: string };
type R1<T> = keyof T;
const O: R1<Obj> = 'age';
利用 [number] 属性
interface ColorMap {
first: 'blue';
secondary: 'red';
three: 'yellow';
}
type FirstColor = ColorMap['first'];
// type NoFirstColor = ColorMap['first'] | ColorMap['secondary']
type NoFirstColor = ColorMap['first' | 'secondary'];
type EveryColor = ColorMap[keyof ColorMap];
type TupleLetters = ['a', 'b', 'c', 1];
type AB = TupleLetters[0 | 1];
type All = TupleLetters[number];
interface UserRole {
admin: ['add', 'delete', 'update'];
user: ['add1', 'delete2'];
}
type Role = UserRole[keyof UserRole][number];
24:
23: 巧用可选属性
type UserRoleType = 'admin' | 'superAdmin'
interface UserType {
name: string;
role?: UserRoleType;
}
const createUser = (user: UserType) => {};
createUser({
name: '小明',
role: 'admin',
})
createUser({
name: '小亮'
})
22: as const
const People = [
'admin',
'user',
'titian'
]
People[0] = 'Eddy';
// 利用 as const 声明为字面量
const tsPeople = [
'admin',
'user',
'titian'
] as const
// 不能通过tsPeople[0] 来进行修改,ts 报错
tsPeople[0] = 'Eddy';
// 对象也是如此
const PeopleObj = {
admin: 'admin',
user: 'user',
titian: 'titian'
} as const
PeopleObj.admin= 'test'
21:
export type Obj = {
a: 'a';
a2: 'ATwo';
a3: 'a3';
b: 'b';
b1: 'b1';
b2: 'b2';
};
type ValuesOfKeysStartWithA<T> = {
[K in Extract<keyof T, `a${string}`>]: T[K];
}[Extract<keyof T, `a${string}`>];
type newUnion = ValuesOfKeysStartWithA<Obj>;
type ValuesOfKeysStartWithAF<T, _ExtractKeys = Extract<keyof T, `a${string}`>> = {
[K in Extract<keyof T, `a${string}`>]: T[K];
}[Extract<keyof T, `a${string}`>];
type newUnion1 = ValuesOfKeysStartWithAF<Obj>;
type ValuesOfKeysStartWithAB<T, _ExtractKeys extends keyof T = Extract<keyof T, `a${string}`>> = {
[K in _ExtractKeys]: T[K];
}[_ExtractKeys];
type newUnion2 = ValuesOfKeysStartWithAB<Obj>;
19:
interface Animal {
name: string;
}
interface Human {
firstName: string;
lastName: string;
}
export const getDisplayName = (item: Animal): { displayName: string } => {
return {
displayName: item.name,
};
};
const result = getDisplayName({
name: 'patch',
});
const result2 = getDisplayName({
firstName: 'bob',
lastName: 'alice',
});
export const getDisplayName1 = (item: Animal | Human): { displayName: string } => {
if ('name' in item) {
return {
displayName: item.name,
};
}
};
const result4 = getDisplayName1({
name: 'patch',
});
const result3 = getDisplayName1({
firstName: 'bob',
lastName: 'alice',
});
export const getDisplayName2 = <TItem extends Animal | Human>(item: TItem): TItem extends Human ? {firstName: string}: {name:string} => {
if ('name' in item) {
return {
name: item.name,
};
}else {
return {
firstName: item.firstName
}
}
};
const result5 = getDisplayName2({
name: 'patch',
});
const result6 = getDisplayName2({
firstName: 'bob',
lastName: 'alice',
});
17: omit 实现?
export type Letters = 'jpg' | 'png' | 'svg';
type RemoveSvg<T> = T extends 'svg' ? never : T;
type Omit<T, K> = T extends K ? never : T;
type WithoutSvg = RemoveSvg<Letters>;
type WithoutPng = Omit<Letters, 'png'>;
16:
export type Event =
| {
type: 'Log_In';
payload: {
userId: string;
};
}
| {
type: 'sign_out';
};
const sendEvent = (eventType: Event['type'], payload?: any) => {};
const sendEvent1 = <Type extends Event['type']>(
...args: Extract<Event, {type: Type}> extends {payload: infer TPayload} ? [type: Type, payload: TPayload] : [type: Type]
) => {}
sendEvent('sign_out');
sendEvent('Log_In', {
userId: '1222',
});
sendEvent('sign_out', {});
sendEvent('Log_In', {
userId: '1222',
});
sendEvent('Log_In', {});
sendEvent('Log_In');
sendEvent1('sign_out',{
})
13
// 如果我们有一个常量文件定义了一些常量,比如 constants 文件中有下面这些
export const ADD_TODO = 'ADD_TODO';
export const REMOVE_TODO = 'REMOVE_TODO';
export const EDIT_TODO = 'EDIT_TODO';
// 但是当我们定义 Action 类型的时候,一般会再手动写一次 type 定义: 如
type ActionType = 'ADD_TODO' | 'REMOVE_TODO' | 'EDIT_TODO';
// 这样的话,当我们常量文件修改的话,对应的 ActionType 也要修改
// 所以我们通过 typeof import('./constants'),将其导出为 ActionModule 类型,typeof 返回的是一个对象类型
export type ActionModule = typeof import('./a');
const actionModule: ActionModule = {
ADD_TODO: 'ADD_TODO',
REMOVE_TODO: 'REMOVE_TODO',
// EDIT_TODO: 'EDIT_TODO'
};
// 利用 keyof 将其转换为 ActionType
export type Action = ActionModule[keyof ActionModule];
12
type Size = 'sm' | 'md' | 'xs' | string;
type SizeTwo = 'sm' | 'md' | 'xs' | Omit<string, 'sm' | 'md' | 'xs'>;
type AutoComplete<T extends string> = T | Omit<string, T>
type SizeThree = AutoComplete<'sm'| 'md' | 'xs'>
- deepPartial
interface User {
id: string;
comment: {
value: string;
}[];
meta: {
name: string;
desc: string;
}
}
const UserAlice: Partial<User> = {
id: 'alice',
comment: [{value: 'name'}],
meta: {
name: 'alice',
// 如果使用Partial,meta 更深层次的属性并不能设为为可选属性,所以需要 deepPartial
}
}
export type DeepPartial<T> = T extends Function
? T
: T extends Array<infer InferredArrayMember>
? DeepPartialArray<InferredArrayMember>
: T extends object
? DeepPartialObject<T>
: T | undefined;
interface DeepPartialArray<T> extends Array<DeepPartial<T>> {}
type DeepPartialObject<T> = {
[K in keyof T]: DeepPartial<T[K]>;
};
10: 将抛出的错误移动到类型提示的级别
// 假设我们有一个参数比较的函数 deepEqualCompare
const deepEqualCompare = <T,>(a: T, b: T): boolean => {
if (Array.isArray(a) || Array.isArray(b)) {
throw new Error('you cannot compare two arrays');
}
return a === b;
};
deepEqualCompare(1, 1);
// 当我们对比数组的时候会抛出错误,我们可以利用 ts 将错误提升到类型级别
deepEqualCompare([], []);
type CheckIsArray<T> = T extends any[] ? 'you cannot compare two arrays' : T;
const deepEqualCompare1 = <T,>(
a: CheckIsArray<T>,
b: CheckIsArray<T>,
): boolean => {
if (Array.isArray(a) || Array.isArray(b)) {
throw new Error('you cannot compare two arrays');
}
return a === b;
};
deepEqualCompare1([], []);
9:
const makeKeyRemove = <Key extends string>(keys: Key[]) => {
return <Obj,>(obj: Obj): Omit<Obj, Key> => {
return {} as any;
};
};
const keyRemover = makeKeyRemove(['a', 'b']);
const newObject = keyRemover({ a: 1, b: 2, c: 3 });
interface TableProps {
items: { id: string }[];
renderItem: (item: { id: string }) => React.ReactNode;
}
export const Table = (props: TableProps) => {
return null;
};
// 有时候,想要在 items 中传递任意属性,而不是只传递 id
const Component = () => {
return (
<Table
items={[{ id: '1', age: 'name' }]}
renderItem={(item) => <div>{item.id}</div>}
></Table>
);
};
interface TableProps1<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
export const Table1 = <T,>(props: TableProps1<T>) => {
return null;
};
const Component1 = () => {
return (
<Table1<{ id: number; age: string }>
items={[{ id: 1, age: 'name' }]}
renderItem={(item) => <div>{item.id}</div>}
></Table1>
);
};
export const myObject = {
a: 1,
b: 2,
c: 3,
};
Object.keys(myObject).forEach((key) => {
console.log(myObject[key as keyof typeof myObject]);
});
// 方法二
const objectKeys = <T extends object>(obj: T): (keyof T)[] => {
return Object.keys(obj) as (keyof T)[];
};
objectKeys(myObject).forEach((key) => {
console.log(myObject[key]);
});
const MyComponent = (props: { enabled: boolean }) => {
return null;
};
class MyOtherComponent extends React.Component<{
enabled: boolean;
}> {}
type PropsFrom<TComponent> = TComponent extends React.FC<infer Props>
? Props
: TComponent extends React.Component<infer Props>
? Props
: never;
const props: PropsFrom<MyOtherComponent> = {
enabled: true,
};
export const getDeepValue = <Obj, FirstKey, SecondKey>(
obj: Obj,
firstKey: FirstKey,
secondKey: SecondKey,
) => {
return {} as any;
};
const obj = {
foo: {
a: true,
b: 2,
},
bar: {
c: 'cool',
d: 2,
},
};
const result = getDeepValue(obj, 'bar', 'd');
export const getDeepValue1 = <
Obj,
FirstKey extends keyof Obj,
SecondKey extends keyof Obj[FirstKey],
>(
obj: Obj,
firstKey: FirstKey,
secondKey: SecondKey,
): Obj[FirstKey][SecondKey] => {
return obj[firstKey][secondKey] as any;
};
const result1 = getDeepValue1(obj, 'foo', 'a');
- 函数重载
// 函数重载
export function compose<Input, FirstArg>(
func: (input: Input) => FirstArg,
): (input: Input) => FirstArg;
export function compose<Input, FirstArg, SecondArg>(
func: (input: Input) => FirstArg,
func2: (input: FirstArg) => SecondArg,
): (input: Input) => SecondArg;
export function compose<Input, FirstArg, SecondArg, ThirdArg>(
func: (input: Input) => FirstArg,
func2: (input: FirstArg) => SecondArg,
func3: (input: SecondArg) => ThirdArg,
): (input: Input) => ThirdArg;
export function compose(...args: any[]) {
return {} as any;
}
const addOne = (a: number) => {
return a + 1;
};
const numToString = (a: number) => {
return a.toString();
};
const stringToNum = (a: string) => {
return parseInt(a);
};
const addOneToString = compose(addOne);
const addTwoToString = compose(addOne, numToString);
const addThreeToString = compose(addOne, numToString, stringToNum);
import { String } from 'ts-toolbelt';
const query = '/home?a=foo&b=wow';
type Query = typeof query;
type SecondQueryPart = String.Split<Query, '?'>[1];
type QueryElements = String.Split<SecondQueryPart, '&'>;
type QueryParams = {
[QueryElement in QueryElements[number]]: {
[Key in String.Split<QueryElement, '='>[0]]: String.Split<
QueryElement,
'='
>[1];
};
}[QueryElements[number]];
const obj: Union.Merge<QueryParams> = {
a: 'foo',
b: 'woo',
};
export type Entity = { type: 'user' } | { type: 'post' } | { type: 'comment' };
type s = keyof Entity;
// 动态添加type的id
type EntityWithId =
| { type: 'user'; userId: string }
| { type: 'post'; postId: string }
| { type: 'comment'; commentId: string };
type EntityWithId1 = {
[EntityType in Entity['type']]: {
type: EntityType;
} & Record<`${EntityType}Id`, string>;
}[Entity['type']];
const entityResult1: EntityWithId1 = {
type: 'user',
userId: 'ss',
};
const entityResult: EntityWithId = {
type: 'user',
userId: '124',
};
- 如何将对象改为联合类型
export const fruitCounts = {
apple: 1,
pear: 4,
banana: 26,
};
type SingleFruitCountType =
| { apple: number }
| { banana: number }
| { pear: number };
const SingleFruitCount: SingleFruitCountType = {
banana: 12,
};
// 修改重构 SingleFruitCountType 这段类型定义代码
type fruitCountsType = typeof fruitCounts;
type newSingleFruitCount = {
[K in keyof fruitCountsType]: {
[K2 in K]: number;
};
}[keyof fruitCountsType];
const SingleFruitCount1: newSingleFruitCount = {
banana: 12,
};
// 联合类型转交叉类型
type UnionToIntersection<U> = (U extends U ? (a: U) => any : never) extends (
a: infer R,
) => any
? R
: never;
type res = UnionToIntersection<{ a: 1 } | { b: 2 }>;
type Copy<Obj> = {
[K in keyof Obj]: Obj[K];
};
type AOrB = keyof res;
type res2 = Copy<UnionToIntersection<{ a: 1 } | { b: 2 }>>;
请教一下 x6 采用自定义节点 绘制 现在要进行 导出png/svg 有大佬处理过吗
用哪个自带的那个方法,导出样式和节点图片会缺失
样式写行内 图片用base64
codeShonwBox
定义联合类型:
function printId(id: number | string) {
console.log('ID is' + id)
}
提供与联合类型匹配的值非常容易,只需要提供一个值,这个值只要与联合类型中国的任意一个成员匹配即可,但是如果有一个联合类型的值,在做操作的时候,这个操作必须对联合类型中的每一个成员都有效
function printId(id: number | string) {
console.log(id.toUpperCase())
// ts 提示错误 toUpperCase 不能用于number
}
解决办法就是缩小类型
function printId(id: number | string) {
if (typeof if === 'string') {
console.log(id.toUpperCase())
} else {
console.log(id)
}
}
const stringToNum = (a: string) => { return parseInt(a); };
const addOneToString = compose(addOne); const addTwoToString = compose(addOne, numToString); const addThreeToString = compose(addOne, numToString, stringToNum);
3.
```ts
import { String } from 'ts-toolbelt';
const query = '/home?a=foo&b=wow';
type Query = typeof query;
type SecondQueryPart = String.Split<Query, '?'>[1];
type QueryElements = String.Split<SecondQueryPart, '&'>;
type QueryParams = {
[QueryElement in QueryElements[number]]: {
[Key in String.Split<QueryElement, '='>[0]]: String.Split<
QueryElement,
'='
>[1];
};
}[QueryElements[number]];
const obj: Union.Merge<QueryParams> = {
a: 'foo',
b: 'woo',
};
const addOneToString = compose(addOne); const addTwoToString = compose(addOne, numToString); const addThreeToString = compose(addOne, numToString, stringToNum);
3.
```ts
import { String } from 'ts-toolbelt';
const query = '/home?a=foo&b=wow';
type Query = typeof query;
type SecondQueryPart = String.Split<Query, '?'>[1];
type QueryElements = String.Split<SecondQueryPart, '&'>;
type QueryParams = {
[QueryElement in QueryElements[number]]: {
[Key in String.Split<QueryElement, '='>[0]]: String.Split<
QueryElement,
'='
>[1];
};
}[QueryElements[number]];
const obj: Union.Merge<QueryParams> = {
a: 'foo',
b: 'woo',
};