CSS

css reset & normalize.css

由于浏览器的实现不同,不同浏览器对标签样式的初始值有些许不同,所以一般通过上面两种方式来做初始值重置。达到重置后表现形式统一的效果。
但 normalize 的影响范围远小于 css reset,css reset 更多会对 p,h 之类常用标签做样式重置(且可能不符合标准)。如果这是一个组件库,极为可能造成样式污染。
所以 normalize 的作用只是做修复型重置及缺失重置,而不对原生特性做修改。
css reset 适合项目开发前重置统一使用,normalize 适合任意场景。
image.png
比较典型的例子就是 p 的 margin-top,原生是 1em(chrome通过margin-block-start实现),很多 css reset 会重置为 0。

margin-block-start & margin-inline-start 是一种更灵活的margin设置方式,主要还是为了适配 rl 相关 https://stackoverflow.com/questions/59909792/what-is-the-difference-between-margin-block-start-and-margin-top

TypeScript

Indexed Access Types & Mapped Types

对应 Type[Key] 操作及 K in Type 操作。
这两个操作常结合起来,用于处理存在 index signatures 的类型结构,对 key 和 property 同时做处理的各种场景。

Indexed Access Types

We can use an indexed access type to look up a specific property on another type: The indexing type is itself a type, so we can use unions, keyof, or other types entirely: Another example of indexing with an arbitrary type is using number to get the type of an array’s elements. We can combine this with typeof to conveniently capture the element type of an array literal<br />

keyof 用于获取拥有 index signatures 的类型的对应类型,像 Array / Tuple / object / Record 都可以通过 其获取 index signatures 类型。
index signatures 类型示例:

  1. type ATuple = [number, string];
  2. type AArray = number[];
  3. type ARecord = Record<string | number, 1>;
  4. type AObject = { a: string; b: number };
  5. type TTT = keyof AObject;
  6. type ATKey = keyof ATuple; // number | keyof ATuple
  7. type AAKey = keyof AArray; // number | keyof AArray
  8. type ARKey = keyof ARecord; // string | number
  9. type AOKey = keyof AObject; // keyof AObject -> 'a' | 'b'
  10. type ATPro = ATuple[number]; // string | number
  11. type AAPro = AArray[number]; // number
  12. type ARPro = ARecord[string]; // 1
  13. type AOPro = AObject['a' | 'b']; // string | number

只要是 可分配于当前类型 index signatures 的类型,都是一个可用的 indexed access type 用于从当前类型中获取对应 property 类型。

Mapped Types

Mapped Types 用于通过 一个 union type 来创建一个新类型的 key 部分 [K in UnionType],这样 UnionType 中的元素类型被遍历作为了 key 类型,且在创建中 K 相当于一个占位获取(infer),可以用于 Value 部分类型参考,如: { [K in keyof T]: T[K] }

A mapped type is a generic type which uses a union of PropertyKeys (frequently created via a keyof) to iterate through keys to create a type: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

更多参考链接:
不太常见的使用方式,可以通过 - 操作符来进行 readonly 或 optianal 的去遍历除:

  1. // Removes 'readonly' attributes from a type's properties
  2. type CreateMutable<Type> = {
  3. -readonly [Property in keyof Type]: Type[Property];
  4. };
  5. // Removes 'optional' attributes from a type's properties
  6. type Concrete<Type> = {
  7. [Property in keyof Type]-?: Type[Property];
  8. };

重要的使用方式

配合 conditional type 在遍历 key类型 时,重写 property类型

[Property in keyof Type] 按 Type 的 key 类型遍历设置新类型的 key 类型;
Type[Property] extends { pii: true } ? true : false; 新类型 property类型可分配 { pii: true } 设为 false,是设为 true

  1. type ExtractPII<Type> = {
  2. [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
  3. };
  4. type DBFields = {
  5. id: { format: "incrementing" };
  6. name: { type: string; pii: true };
  7. };
  8. type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;
  9. //type ObjectsNeedingGDPRDeletion = {
  10. // id: false;
  11. // name: true;
  12. //}

获取 property类型中 非函数类型的 key union:

[K in keyof T] 按 T 的 key 类型遍历设置新类型的 key 类型;
T[K] extends Function ? never : K; 新类型 对应key 的 property类型 可分配 Function 设为 never,否则为 key 类型
NewType[keyof T] 新类型 按 原类型 key类型的 union,获得 property类型的 union,新类型的 property类型 部分的 never 就被省略了,剩下的也就是 原类型非Function 的 key 类型 组成的 union。

  1. type noFunctionKeys<T> = {
  2. [K in keyof T]: T[K] extends Function ? never : K; // 生成 { key: T[key]是函数 ? never : key }
  3. }[keyof T];

综合

修改 type Connect = (module: EffectModule) => any; 中的 any;
const connected: Connected = connect(new EffectModule()); 返回类型符合声明的类型。

  1. interface Action<T> {
  2. payload?: T;
  3. type: string;
  4. }
  5. class EffectModule {
  6. count = 1;
  7. message = 'hello!';
  8. delay(input: Promise<number>, out: Promise<number>) {
  9. return input.then((i) => ({
  10. payload: `hello ${i}!`,
  11. type: 'delay',
  12. }));
  13. }
  14. setMessage(action: Action<Date>) {
  15. return {
  16. payload: action.payload!.getMilliseconds(),
  17. type: 'set-message',
  18. };
  19. }
  20. }
  21. type Connect = (module: EffectModule) => any;
  22. const connect: Connect = (m) => ({
  23. delay: (input: number, out: number) => ({
  24. type: 'delay',
  25. payload: `hello 2`,
  26. }),
  27. setMessage: (input: Date) => ({
  28. type: 'set-message',
  29. payload: input.getMilliseconds(),
  30. }),
  31. });
  32. type Connected = {
  33. delay(input: number, out: number): Action<string>;
  34. setMessage(action: Date): Action<number>;
  35. };
  36. const connected: Connected = connect(new EffectModule());
  1. type noFunctionKeys<T> = {
  2. [K in keyof T]: T[K] extends Function ? never : K;
  3. }[keyof T];
  4. type FunctionPropertiesObj = Omit<EffectModule, noFunctionKeys<EffectModule>>;
  5. type UnPromisify<T> = T extends Promise<infer U> ? U : T;
  6. type UnAction<T> = T extends Action<infer U> ? U : T;
  7. // 对于 可分配于 any[]类型,去除Promise和Action
  8. // 其他去除Promise
  9. type MapTypeToUnPromisifyAndUnAction<T> = T extends any[]
  10. ? {
  11. [K in keyof T]: UnAction<UnPromisify<T[K]>>;
  12. }
  13. : UnPromisify<T>;
  14. // 对于符合的 函数类型,infer 获取 param 和 return 的类型,进行 unpack
  15. type UnpackFunc<F> = F extends (...args: infer P) => infer T
  16. ? (
  17. ...args: MapTypeToUnPromisifyAndUnAction<P>
  18. ) => MapTypeToUnPromisifyAndUnAction<T>
  19. : never;
  20. // map所有property进行unpack操作
  21. type Out<T> = { [K in keyof T]: UnpackFunc<T[K]> };
  22. type Connect = (module: EffectModule) => Out<FunctionPropertiesObj>;