gpt4 book ai didi

typescript - 将字段映射到一起的正确 TS 声明

转载 作者:行者123 更新时间:2023-12-04 07:24:18 24 4
gpt4 key购买 nike

我有一个 AccountDefinition看起来像这样:

something: {
type: 'client',
parameters: {
foo: 3
}
},
other: {
type: 'user',
parameters: {
bar: 3
}
},
...
TS 声明工作正常,但我现在正在尝试创建一个“生成器”( doThings )函数并遇到如何正确键入它的挑战。我也愿意重构所有这些类型。
export interface Spec {
type: `${SpecType}`
parameters: unknown
}

export interface UserSpec extends Spec {
type: `${SpecType.USER}`
parameters: UserSpecParameters
}

export interface ClientSpec extends Spec {
type: `${SpecType.CLIENT}`
parameters: ClientSpecParameters
}

export interface AccountDefinition {
[k: string]: UserSpec | ClientSpec
}

export enum SpecType {
USER = 'user',
CLIENT = 'client'
}

export type SpecParametersMap = {
user: {
bar?: number
}
client: ClientSpecParameters
}

export interface UserSpecParameters {
bar?: number
}

export interface ClientSpecParameters {
foo: number
}

export const doThing = <T extends SpecType>( // Ideally not a generic if it can infer parameters from type
type: T,
parameters: SpecParametersMap[T]
): void => {
const account: AccountDefinition = {
// Example
foo: {
type: 'client',
parameters: {
foo: 3
}
},
// TS Error:
// Type '{ parameters: SpecParametersMap[T]; type: T; }' is not assignable to type 'UserSpec | ClientSpec'.
// Type '{ parameters: SpecParametersMap[T]; type: T; }' is not assignable to type 'ClientSpec'.
// Types of property 'type' are incompatible.
// Type 'T' is not assignable to type '"client"'.ts(2322)
data: {
parameters,
type
}
}
}

doThing(SpecType.CLIENT, { foo: 4 })
游乐场 link

最佳答案

这里的问题在于争论。 TS 不将它们视为一种数据结构的一部分。
为了使它工作,您应该将您的参数合并到一个数据结构中。

export enum SpecType {
USER = 'user',
CLIENT = 'client'
}

export interface Spec {
type: `${SpecType}`
parameters: unknown
}

export interface ClientSpecParameters {
foo: number
}

export interface UserSpecParameters {
bar?: number
}

export interface UserSpec extends Spec {
type: `${SpecType.USER}`
parameters: UserSpecParameters
}

export interface ClientSpec extends Spec {
type: `${SpecType.CLIENT}`
parameters: ClientSpecParameters
}

type AllowedValues = UserSpec | ClientSpec;

export interface AccountDefinition {
[k: string]: AllowedValues
}


export const doThing = (data: AllowedValues): void => {
const account: AccountDefinition = {
foo: {
type: 'client',
parameters: {
foo: 3
}
},
data
}
}

doThing({ type: SpecType.CLIENT, parameters: { foo: 4 } }) // ok
doThing({ type: SpecType.USER, parameters: { bar: 42 } }) // ok


您也可以使用 this方法,但正如您可能已经注意到的那样,没有很好的解构

Why can't the generic param be used to get both arguments?


你可以,事实上有几种方法可以做到这一点。在这里你有其中之一:
export const doThing = <T extends SpecType>(data: T extends SpecType.CLIENT ? ClientSpec : UserSpec): void => {
const account: AccountDefinition = {
foo: {
type: 'client',
parameters: {
foo: 3
}
},
data
}
}

doThing({ type: SpecType.CLIENT, parameters: { foo: 4 } }) // ok
doThing({ type: SpecType.USER, parameters: { bar: 42 } }) // ok

doThing({ type: SpecType.USER, parameters: { foo: 4 } }) // expected error
doThing({ type: SpecType.CLIENT, parameters: { bar: 42 } }) // expected error

关于typescript - 将字段映射到一起的正确 TS 声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68304681/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com