简体   繁体   English

通过兄弟属性推断 object 类型 - Typescript

[英]Infer object types by sibling property - Typescript

Is it possible to assert properties of an object based on another property within that same object?是否可以根据同一 object 中的另一个属性断言 object 的属性?

But how can I infer the types for values based on the value of type property?但是如何根据type属性的values推断值的类型呢?

type StepKeys = "Test1" | "Test2";

interface objectMap {
    "Test1": {
        name: string
    },
    "Test2": {
        age: number
    }
};

interface Step<T extends StepKeys = StepKeys> {
    type: T;
    value: objectMap[T]
};

const steps: Record<string, Step> = {
    "Step1": {
        type: "Test1",
        value: {

        }
    }
}

Here types for values are a union of { name: string; } | { age: number; }这里values的类型是{ name: string; } | { age: number; } { name: string; } | { age: number; } { name: string; } | { age: number; } . { name: string; } | { age: number; }

Is it possible to infer it's possible values?是否可以推断出它的可能值?

Typescript Typescript

Hi should you want to effectively discriminate this union, the type parameter should not be a union, instead seek to "push" the union one type up.你好,如果你想有效地区分这个联合,类型参数不应该是一个联合,而是寻求将联合“推”到一种类型。 This is because we want each Step type to have it's own unique type parameter, instead of the union of possible type parameters.这是因为我们希望每个Step类型都有自己唯一的类型参数,而不是可能类型参数的联合。 So a small change, but accomplishes what you want.所以一个小的改变,但完成你想要的。

const steps: Record<string, Step<'Test1'> | Step<'Test2'>> = {
    "Step1": {
        type: "Test1",
        value: {
            // infer ?
            age: 11,
// ^^^ correctly throws error 
// Object literal may only specify known properties, and 'age' does not exist in type '{ name: string; }'.(2322)
            name: 'test',
        }
    }
}

Using an indexed access map type you can create a discriminated union automatically if there are a lot more key/value pairs.使用索引访问 map 类型,如果有更多的键/值对,您可以自动创建可区分的联合。

type Steps = Record<string, {
    [key in StepKeys]: Step<key>
}[StepKeys]>

View on TS Playground在 TS 游乐场上查看

The only way to achieve what you want isn't really good but it works.实现你想要的东西的唯一方法并不是很好,但它确实有效。 The problem is that you have to manually enter every key (which makes it impossible to make it generic or scalable).问题是你必须手动输入每个密钥(这使得它不可能通用或可扩展)。

interface PeoplePropsMap {
    withName: {
        name: string
    },

    withAge: {
        age: number
    }
};

type People =
    { type: 'withName', value: PeoplePropsMap['withName'] } |
    { type: 'withAge',  value: PeoplePropsMap['withAge']  }

const steps: Record<string, People> = {
    john: {
        type: 'withAge',
        value: {
            age: 10  
        }
    }
}

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

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