简体   繁体   English

Typescript 接口值作为枚举或记录

[英]Typescript interface value as enum or Record

Suppose I have some object that could have either key as string and value as either enum or object with key and value as enum.假设我有一些 object 可以将key作为字符串,将value作为enum或 object,将键和值作为枚举。

types类型

export enum ERRORS {
  ERROR1 = 'Error1',
  ERROR2 = 'Error2',
}

export type ErrorType = 'blue' | 'green';

export interface ErrorByCode {
  [key: string]: ERRORS | Record<ErrorType, ERRORS>;
}

code代码

const ERRORS_BY_CODE: ErrorByCode = {
  default: ERRORS.ERROR1,
  '01': ERRORS.ERROR2,

  '2': {
    blue: ERRORS.ERROR1,
    green: ERRORS.ERROR2,
  },
};

const errorResolver = ({code, type}: {code: string; type: ERRORS}) => {
    const errorMessage =
    (ERRORS_BY_CODE?.[code] || ERRORS_BY_CODE?.[code]?.[type]) ??
    ERRORS_COMPONENTS_BY_CODE.default;

    return errorMessage
};


console.log(errorResolver({code: '01', type: 'blue'}))



But I've got ts error under ERRORS_BY_CODE?.[code]?.[type] Element implicitly has an 'any' type because expression of type 'ErrorType' can't be used to index type 'ERRORS |但是我在ERRORS_BY_CODE?.[code]?.[type]下出现 ts 错误,因为“ErrorType”类型的表达式不能用于索引类型“ERRORS | Record<ErrorType, ERRORS>'.记录<错误类型,错误>'。 Property 'blue' does not exist on type 'ERRORS_BY_CODE |类型 'ERRORS_BY_CODE | 上不存在属性'蓝色' Record<InsuranceType, ERROR_COMPONENTS>'.记录<InsuranceType,ERROR_COMPONENTS>'。

The compiler does not expect anyone to try to index into a string (which ERRORS is) with a key like "blue" , and it does not allow it.编译器不希望任何人尝试使用"blue"之类的键对stringERRORS是)进行索引,并且它不允许这样做。 It will consider that property to be of type any , and give a compile error:它将认为该属性的类型为any ,并给出编译错误:

function nope(str: string) {
    str.blue // error! Property 'blue' does not exist on type 'string'
}

If a value is of a type which is a union of string and something else, the compiler will also be unhappy about such an indexing, since it might be a string for all it knows:如果一个值的类型是string和其他东西的联合,编译器也会对这样的索引不满意,因为它可能是它所知道的所有string

function stillNope(uni: string | { blue: number }) {
    uni.blue // error! Property 'blue' does not exist on type 'string'
}

Optional chaining does not fix this. 可选链接不能解决这个问题。 You are not allowed to access an unknown property on an object even if you use ?.即使您使用?. instead of .而不是. . . This prohibition is intentional;这种禁止是故意的; see microsoft/TypeScript#33736 for more information.有关详细信息,请参阅microsoft/TypeScript#33736


If you want to access a property on a union type where at least one of the members of the union is not known to have that property, you will need to use some other form of type guarding.如果要访问联合类型上的属性,其中至少有一个联合成员不知道具有该属性,则需要使用其他形式的类型保护。 One way is to use typeof guarding :一种方法是使用typeof保护

function typeofGuard(
  uni: ERRORS | { blue: ERRORS, green: ERRORS }, 
  type: ErrorType
) {
    const errors = typeof uni === "string" ? uni : uni[type];
}

The other possibility is to represent your union as one where each member of the union has known behavior at the ErrorType keys.另一种可能性是将您的工会表示为工会的每个成员在ErrorType键上都有已知行为的工会。 Instead of ERRORS , which is a string with no known behavior at ErrorType , you can make it ERRORS & {[P in ErrorType]?: undefined } .而不是ERRORS ,这是一个在ErrorType没有已知行为的string ,您可以将其设为ERRORS & {[P in ErrorType]?: undefined } Meaning: it is ERRORS , and if you index into it with an ErrorType key, you will get an undefined property.含义:它是ERRORS ,如果您使用ErrorType键对其进行索引,您将获得一个undefined的属性。 This makes your error go away also:这也会使您的错误 go 消失:

function exclusiveUnion(
    uni: (ERRORS & { [P in ErrorType]?: undefined }) | (Record<ErrorType, ERRORS>),
    type: ErrorType
) {
    const errors = uni[type]; // ERRORS | undefined
}

Playground link to code Playground 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM