在对象内将一种 TypeScript 类型与另一种类型交换

Swap one TypeScript type with another inside an object

我有以下类型:

type Target = number | undefined;

type MyObject = {
    some: string;
    properties: string;
    id: Target;
}

我想想出一个通用的方法来用 number 替换 Target,比如:

type MyObjectTransformed = TargetToNumber<MyObject>;

/**
 * MyObjectTransformed is now:
 * 
 * {
 *     some: string;
 *     properties: string;
 *     id: number;
 * }
 */

如果您知道 Target 总是在 id 字段中,就很容易了,我不需要这方面的帮助。

但是如果 Target 可以在任何地方呢?像这样也应该有效:

TargetToNumber<{
    some: string;
    other: Target;
    properties: string;
}>

更糟糕的是...它在嵌套时也需要工作!像这样应该仍然用 number:

替换 Target
TargetToNumber<{
    some: string;
    properties: string;
    nested: {
        arbitrarily: {
            deep: Target;
        };
    };
}>

如果你好奇我为什么要做这么奇怪的事情,this is why I'm asking

使用条件类型:如果任意类型 TAA 的子类型,我们将其替换为 B,否则如果它是一个对象type 我们递归映射属性,否则我们将类型保留为 T.

type TargetToNumber<T> = SubstituteType<T, Target, number>;

type SubstituteType<T, A, B> =
    T extends A
    ? B
    : T extends {}
    ? { [K in keyof T]: SubstituteType<T[K], A, B> }
    : T;

如果您只想完全替换 A 并单独保留 A 的子类型(例如 never 始终是子类型...),您可以替换 T extends A[A, T] extends [T, A] 来测试它们是同一类型。

Playground Link