方法順序執行,不論同步還是異步
以下代碼實現方法順序執行,不論同步還是異步,
let result;
for (const f of [func1, func2, func3]) {
result = await f(result);
}
/* use last result (i.e. result3) */
更老版本的寫法:
const applyAsync = (acc, val) => acc.then(val);
const composeAsync =
(...funcs) =>
(x) =>
funcs.reduce(applyAsync, Promise.resolve(x));
const transformData = composeAsync(func1, func2, func3);
const result3 = transformData(data);
參考:MDN: 使用Promise[1]
閉包緩存計算結果,提高性能
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key] !== undefined) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
const memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // 輸出 55
console.log(memoizedFibonacci(20)); // 輸出 6765
在這個例子中,memoize
函數通過閉包緩存了計算結果,提高了遞歸函數的性能。
閉包實現函數柯里化
通用的函數柯里化工具函數,注意這里沒有處理this
的指向
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
}
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
};
}
function sum(a,b,c){
return a+b+c;
}
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6
TypeScript
枚舉+位運算進行狀態判斷
枚舉+位運算進行狀態判斷與運算
enum AnimalFlags {
None = 0,
HasClaws = 1 << 0,
CanFly = 1 << 1
}
interface Animal {
flags: AnimalFlags;
[key: string]: any;
}
function printAnimalAbilities(animal: Animal) {
var animalFlags = animal.flags;
if (animalFlags & AnimalFlags.HasClaws) {
console.log('animal has claws');
}
if (animalFlags & AnimalFlags.CanFly) {
console.log('animal can fly');
}
if (animalFlags == AnimalFlags.None) {
console.log('nothing');
}
}
var animal = { flags: AnimalFlags.None };
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws;
printAnimalAbilities(animal); // animal has claws
animal.flags &= ~AnimalFlags.HasClaws;
printAnimalAbilities(animal); // nothing
animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly;
printAnimalAbilities(animal); // animal has claws, animal can fly
Animal 有多種狀態時判斷、運算十分簡潔
假如讓我來寫的話,不用枚舉+位運算的話可能實現如下
type AnimalFlags = 'None' | 'HasClaws' | 'CanFly';
interface Animal {
flags: AnimalFlags[];
[key: string]: any;
}
function printAnimalAbilities(animal: Animal) {
var animalFlags = animal.flags;
if (!animalFlags || animalFlags.includes('None')) {
return 'nothing';
}
if (animalFlags.includes('HasClaws')) {
console.log('animal has claws');
}
if (animalFlags.includes('CanFly')) {
console.log('animal can fly');
}
}
var animal: Animal = { flags: ['None'] };
printAnimalAbilities(animal); // nothing
animal.flags = ['HasClaws'];
printAnimalAbilities(animal); // animal has claws
animal.flags = ['None'];
printAnimalAbilities(animal); // nothing
animal.flags = ['HasClaws', 'CanFly'];
printAnimalAbilities(animal); // animal has claws, animal can fly
運算不太方便,比如狀態是['HasClaws', 'CanFly']
, 想移除Fly狀態需要進行數組操作,比位運算麻煩許多
參考:深入理解 TypeScript:枚舉[2]
React 導出 useImperativeHandle 的聲明
定義:
type CountdownProps = {}
type CountdownHandle = {
start: () => void,
}
const Countdown: React.ForwardRefRenderFunction<CountdownHandle, CountdownProps> = (
props,
forwardedRef,
) => {
React.useImperativeHandle(forwardedRef, ()=>({
start() {
alert('Start');
}
}));
return <div>Countdown</div>;
}
export default React.forwardRef(Countdown);
在上層組件中常想知道子組件useImperativeHandle
的定義,可以這么寫:
const App: React.FC = () => {
// 這個類型等于 `CountdownHandle`,但不需要手動 import CountdownHandle
type CountDownRef = React.ElementRef<typeof Countdown>;
const ref = React.useRef<CountDownRef>(null); // assign null makes it compatible with elements.
return (
<Countdown ref={ref} />
);
};
CountDownRef
這個類型等于 CountdownHandle
,但不需要手動 import CountdownHandle
參考:stackoverflow[3]
+
-
修飾符
+
-
修飾符可以添加或去掉readonly
和 ?
,如
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property];
};
type LockedAccount = {
readonly id: string;
readonly name: string;
};
type UnlockedAccount = CreateMutable<LockedAccount>;
// UnlockedAccount 等效于
type UnlockedAccount = {
id: string;
name: string;
}
通過as
重新映射類型
在TypeScript 4.1及更高版本中,可以在映射類型中使用as子句重新映射映射類型中的鍵,形式如下:
type MappedTypeWithNewProperties<Type> = {
[Properties in keyof Type as NewKeyType]: Type[Properties]
}
示例一,根據已知類型的鍵映射出新類型鍵
Capitalize[4]: 轉換字符串類型第一個字母為大寫
type Getters<Type> = {
[Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
interface Person {
name: string;
age: number;
location: string;
}
type LazyPerson = Getters<Person>;
// 最終LazyPerson 等效于
type LazyPerson = {
getName: () => string;
getAge: () => number;
getLocation: () => string;
}
示例二:映射任意聯合類型
如:映射聯合對象類型,并以類型的Value為新類型的key
type EventConfig<Events extends { kind: string }> = {
[E in Events as E["kind"]]: (event: E) => void;
}
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };
type Config = EventConfig<SquareEvent | CircleEvent>
// 最終config等效于
type Config = {
square: (event: SquareEvent) => void;
circle: (event: CircleEvent) => void;
}
該文章在 2025/1/24 16:54:47 編輯過