求大佬,这样的情况typescript如何定义对象?

已知有一个对象,key和value对应

{
    a: { a1: 1 },
    b: { b9: 1 },
    c: { c5: 1 },
    d: { d2: 1 },
    ...
}

怎么用ts来定义这样的数组?

[{
    type: 'e',
    value: { e1: 1 }
}, {
    type: 'c',
    value: { c5: 1 }
}]
阅读 2.2k
3 个回答

研究了一下,这个问题可以分为两个部分

  1. 如何约束转化函数的入参类型

利用 template type 很方便可以解决:

type Src<Ks extends string> = {
    [K in Ks]: {
        [P in `${K}${number}`]: number
    }
}

const conv = <Ks extends string>(src: Src<Ks>) => {}
  1. 如何推导返回值类型:

我能想到的是 record 转 union 转 array,其中 UnionToArray 参考了网上的文章。

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I
) => void
    ? I
    : never

type UnionToOvlds<U> = UnionToIntersection<
    U extends any ? (f: U) => void : never
>

type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never

type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true

type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
    ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
    : [T, ...A]

type Src<Ks extends string> = {
    [K in Ks]: {
        [P in `${K}${number}`]: number
    }
}

const conv = <Ks extends string, T extends Src<Ks>>(src: T) => {
    const dist: { type: string, value: { [K: string]: number } }[] = []
    for (const k in src) {
        dist.push({ type: k, value: src[k] })
    }
    return dist as UnionToArray<{
        [K in keyof T]: {
            type: K
            value: T[K]
        }
    }[keyof T]>
}

const dist = conv(src)
//    ^?
//    const dist: [{
//        type: "a";
//        value: {
//            a1: number;
//        };
//    }, {
//        type: "b";
//        value: {
//            b9: number;
//        };
//    }, {
//        type: "c";
//        value: {
//            c5: number;
//        };
//    }, {
//        type: "d";
//        value: {
//            d2: number;
//        };
//    }]

遗憾的是这两个思路不能共存于一个函数(在我看来),你可以按需求选择入参约束或返回类型。

type KeyValuePair = { [key: string]: number };

type ObjectType = {
  type: string;
  value: KeyValuePair;
};

type ObjectArray = ObjectType[];

// 使用
const objects: ObjectArray = [
  {
    type: 'e',
    value: { e1: 1 }
  },
  {
    type: 'c',
    value: { c5: 1 }
  }
];

一个并不完善的 type

type Obj = {
  [props: string]: {
    [props: string]: number;
  };
};

type Pack<T extends Obj> = {
  type: keyof T;
  value: T[keyof T];
}[];

测试使用

const obj = {
  a: { a1: 1 },
  b: { b9: 1 },
  c: { c5: 1 },
  d: { d2: 1 },
};

const goodVal: Pack<typeof obj> = [
  {
    type: "a",
    value: { a1: 10 },
  },
  {
    type: "c",
    value: { c5: 1 },
  },
];

const badVal: Pack<typeof obj> = [
  {
    type: "e",
    value: { e1: 1 },
  },
  {
    type: "f",
    value: { f6: 1 },
  },
];

之所以说不完善,是因为没有限制 valuekey 必须包含 type 前缀:

const val: Pack<typeof obj> = [
  {
    type: "a",
    // 应该为 "a1"
    value: { b9: 1 },
  },
  {
    type: "d",
    // 应该为 ”d2“
    value: { a1: 1 },
  },
];
推荐问题
logo
Microsoft
子站问答
访问
宣传栏