能否从TypeScript中的嵌套对象值创建类型

能否从TypeScript中的嵌套对象值创建类型,typescript,Typescript,如果我们有一个像 const Colors = { Orange: { Light: "#230498", Dark: "#867583", }, Blue: { Light: "#768493", Dark: "#039583", }, } 可以从颜色对象创建一个类型来限制这样的参数吗 function setColor(color: SomeType){ .... } // All

如果我们有一个像

const Colors = {

    Orange: {
        Light: "#230498",
        Dark: "#867583",
    },

    Blue: {
        Light: "#768493",
        Dark: "#039583",
    },
}
可以从颜色对象创建一个类型来限制这样的参数吗

function setColor(color: SomeType){
    ....
}

// Allowed
setColor(Colors.Orange.Light);
setColor(Colors.Blue.Dark);

// Not Allowed
setColor('#ffffff');
setCOlor(SomeOtherObject.Color.Blue.Dark);

我想有人能写出比我更简洁的东西。我建议将Colors对象声明为const,但还有其他方法,重要的是不允许TS扩展颜色类型

const Colors = {
    Orange: {
        Light: "#230498",
        Dark: "#867583",
        Blur: "ffff"
    },

    Blue: {
        Light: "#768493",
        Dark: "#039583"
    },
    Jam: {
        Blur: "df"
    }
} as const;

const SomeOtherObject = {
    Color: { Blue: { Dark: "#039583" } }
} as const;

type C = typeof Colors;

// courtesy of https://github.com/Microsoft/TypeScript/issues/31192
type ObjKeyof<T> = T extends object ? keyof T : never;
type KeyofKeyof<T> = ObjKeyof<T> | { [K in keyof T]: ObjKeyof<T[K]> }[keyof T];
type StripNever<T> = Pick<T, { [K in keyof T]: [T[K]] extends [never] ? never : K }[keyof T]>;
type Lookup<T, K> = T extends any ? (K extends keyof T ? T[K] : never) : never;
type SimpleFlatten<T> = T extends object
    ? StripNever<
        {
            [K in KeyofKeyof<T>]:
                | Exclude<K extends keyof T ? T[K] : never, object>
                | { [P in keyof T]: Lookup<T[P], K> }[keyof T];
        }
    >
    : T;

type A = SimpleFlatten<C>;

type AllowedCols = A[keyof A];

function setColor(color: AllowedCols) {}

setColor(Colors.Orange.Dark);

// This has to be allowed, it's just the nature of TS
setColor(SomeOtherObject.Color.Blue.Dark);

// not allowed
setColor("#fffff");
const Colors={
橙色:{
灯光:“230498”,
黑暗:“867583”,
模糊:“ffff”
},
蓝色:{
灯光:“768493”,
深色:“039583”
},
堵塞:{
模糊:“df”
}
}作为常量;
const SomeOtherObject={
颜色:{蓝色:{深色:{039583}
}作为常量;
C型=颜色类型;
//承蒙https://github.com/Microsoft/TypeScript/issues/31192
类型ObjKeyof=T扩展对象?基特:永远不会;
类型KeyofKeyof=ObjKeyof |{[K in keyof T]:ObjKeyof}[keyof T];
类型StripNever=拾取;
type Lookup=T扩展了任何?(K)T?T[K]:从不:从不;
类型SimpleFlatten=T扩展对象
? 脱衣舞娘<
{
[K in KeyofKeyof]:
|排除
|{[P in keyof T]:查找}[keyof T];
}
>
:T;
A型=简易车床;
类型AllowedCols=A[keyof A];
函数setColor(颜色:AllowedCols){}
setColor(颜色。橙色。深色);
//这是必须允许的,这只是TS的本质
setColor(SomeOtherObject.Color.Blue.Dark);
//不准
设置颜色(“fffff”);
编辑-我以前写的是垃圾,有一段时间没有做任何打字稿…,幸运的是我们的人jcalz来拯救这一天


对于这个用例,我认为没有必要使用通用的扁平化。与CountingStaff的答案类似,您需要将带有
的颜色对象声明为const
,以防止rgb值类型扩展为
字符串,但是下面的代码应该可以完成这项工作。()

type Color=记录
类型调色板=记录
类型ColorRgb=C[keyof C]
键入PaletteRgb=ColorRgb
常量颜色={
橙色:{
灯光:“230498”,
深色:“867583”
},
蓝色:{
灯光:“768493”,
黑暗:“039583”,
veryDark:“000001”
}
}常量
const someOtherObject={
颜色:{蓝色:{深色:{039583],浅色:{fefeff}
}常量
键入ValidRgb=paletergb//ValidRgb=“#230498”|“#867583”|“#768493”|“#039583”|“|000001”
函数setColor(颜色:ValidRgb){}
//允许
设置颜色(颜色。橙色。灯光);
设置颜色(颜色。蓝色。深色);
setColor(someOtherObject.color.blue.dark);//允许,不能避免,因为“#039583”是“颜色”中的有效rgb。
//不准
设置颜色(“ffffff”);
setColor(someOtherObject.color.blue.light);

更好的是,我更喜欢这个答案。我会同意这个计划的。谢谢!我对你关于并非所有颜色共享的关键点的见解投了赞成票。
type Color = Record<string, string>
type Palette = Record<string, Color>
type ColorRgb<C extends Color> = C[keyof C]
type PaletteRgb<P extends Palette> = ColorRgb<{[K in keyof P]: ColorRgb<P[K]>}>

const colors = {
  orange: {
    light: "#230498",
    dark: "#867583"
  },
  blue: {
    light: "#768493",
    dark: "#039583",
    veryDark: "#000001"
  }
} as const

const someOtherObject = {
  color: { blue: { dark: "#039583", light: "#fefeff" } }
} as const

type ValidRgb = PaletteRgb<typeof colors> // ValidRgb = "#230498" | "#867583" | "#768493" | "#039583" | "#000001"

function setColor(color: ValidRgb) {}

// Allowed
setColor(colors.orange.light);
setColor(colors.blue.dark);
setColor(someOtherObject.color.blue.dark); // allowed, cannot be avoided as "#039583" is a valid rgb in `colors`.

// Not Allowed
setColor("#ffffff");
setColor(someOtherObject.color.blue.light);