如何从接口键和键值创建字符串文字类型



假设我们有一个接口和一个enum

enum Destination = {
Home = 'home',
Cafe = 'cafe'
}
interface Payload {
apiVersion: string;
destination: Destination;
email?: string;
}

我想创建一个模板文字类型,它将接口键作为开始和结束标记,并将键值作为标记值。

const condensedPayload: CondensedPayload = '<payload><apiVersion>2.1</apiVersion><destination>home</destination><email>asd@asd.com</email></payload>'

我已经尝试创建这样的CondensedPayload

type CondensedPayload = `<payload><${keyof Payload}>${Payload[keyof Payload]}</${keyof Payload}></payload>`

结果:

  1. 关闭标签名称不一样的开始标记名称,反之亦然,没有得到一个错误
    • const payload: CondensedPayload = '<payload><apiVersion>2.0</destination></payload>' // no error
  2. 不插入所需的键不会得到错误
    • const payload: CondensedPayload = '<payload><email>asd@asd.com</email></payload>' // no error
  3. 插入只有一个关键要求不得到一个错误
    • const payload: CondensedPayload = '<payload><apiVersion>2.0</apiVersion><email>asd@asd.com</email></payload>' // no error
  4. <destination>some string</destination>上插入Destination外的字符串没有得到错误

是否有一种方法来匹配打开,关闭和值,比如迭代keyof Payload和值类型?

可能吗?是的。你应该这么做吗?也许不是…

下面的解决方案将生成对给定Payload类型有效的所有可能的字符串文字类型组合。

type Expand<T> = T extends infer U ? { [K in keyof U]: U[K] } : never
type OptionalProps<T extends object> = Exclude<{
[K in keyof T]: T extends Record<K, T[K]>
? never
: K
}[keyof T], undefined>
type AllPermutations<T extends string, O extends string> = [T] extends [keyof T] ? [] : {
[K in T]: 
K extends O 
? [
...(AllPermutations<Exclude<T, K>, O> extends infer U extends string[] 
? U 
: never)
]
| [
K, ...(AllPermutations<Exclude<T, K>, O> extends infer U extends string[] 
? U 
: never)
]
: [
K, ...(AllPermutations<Exclude<T, K>, O> extends infer U extends string[] 
? U 
: never)
]
}[T]
type Join<T extends string[]> = 
T extends [infer L extends string, ...infer R extends string[]]
? `${L}${Join<R>}`
: ""
type CreatePayloadString<T extends string[], P extends Record<string, any>> = 
T extends [infer L extends string, ...infer R extends string[]]
? `<${L}>${P[L & keyof P]}</${L}>${CreatePayloadString<R, P>}` 
: ""
type CondensedPayload = {
[K in AllPermutations<keyof Payload, OptionalProps<Payload>> as Join<K>]: 
`<payload>${CreatePayloadString<K, Payload>}</payload>`
} extends infer O ? O[keyof O] : never

一些测试:

// Error 
const payload1: CondensedPayload = '<payload><apiVersion>2.0</destination></payload>'
const payload2: CondensedPayload = '<payload><email>asd@asd.com</email></payload>'
const payload3: CondensedPayload = '<payload><apiVersion>2.0</apiVersion><email>asd@asd.com</email></payload>'
const payload4: CondensedPayload = '<payload><apiVersion>abc</apiVersion><destination>some string</destination></payload>'
// Valid
const payload4: CondensedPayload = '<payload><apiVersion>abc</apiVersion><destination>home</destination></payload>'

但是,严肃地说,使用XML解析器来处理这样的事情,甚至更好:不要使用XML。

游乐场

相关内容

  • 没有找到相关文章

最新更新