type-challenges:BEM style string

74 阅读1分钟

BEM style string

问题描述

块、元素、修饰符方法 (BEM) 是 CSS 中类的流行命名约定。

例如,块组件将表示为btn,依赖于块的元素将表示为btn__price,改变块样式的修饰符将表示为btn--bigbtn__price--warning

实现BEM<B, E, M>从这三个参数生成字符串并集。其中B是字符串文字,EM字符串数组(可以为空)。

// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'type cases = [
  Expect<Equal<BEM<'btn', ['price'], []>, 'btn__price'>>,
  Expect<Equal<BEM<'btn', ['price'], ['warning', 'success']>, 'btn__price--warning' | 'btn__price--success'>>,
  Expect<Equal<BEM<'btn', [], ['small', 'medium', 'large']>, 'btn--small' | 'btn--medium' | 'btn--large'>>
]
​
// ============= Your Code Here =============
// 答案1
type IsNever<T> = [T] extends [never] ? true : false
type IsUnion<U> = IsNever<U> extends true ? "" : U
type BEM<B extends string, E extends string[], M extends string[]> = `${B}${IsUnion<`__${E[number]}`>}${IsUnion<`--${M[number]}`>}`
// 答案2
type BEM<B extends string, E extends string[], M extends string[]> = `${B}${E extends [] ? '' : `__${E[number]}`}${M extends [] ? '' : `--${M[number]}`}`

我们知道可以通过下标来将数组或者对象转成联合类型

// 数组
T[number]
// 对象  
Object[keyof T]

特殊的,当字符串中通过这种方式申明时,会自动生成新的联合类型,例如这题下面的写法,

type BEM<B extends string, E extends string[], M extends string[]> = `${B}__${E[number]}--${M[number]}`

会得到 type A = "btn__price--warning" | "btn__price--success" 这样的结果,但是这并没有考虑到空数组的情况,因此需要做提前的判断。

type IsNever<T> = [T] extends [never] ? true : false
type IsUnion<U> = IsNever<U> extends true ? "" : U
type BEM<B extends string, E extends string[], M extends string[]> = `${B}${IsUnion<`__${E[number]}`>}${IsUnion<`--${M[number]}`>}`

还是答案2看着简单些。