存在单个接口IStorage,其中每个键具有两种类型:

interface IStorage {
    key: boolean | CustomStore<boolean>,
    key2: number | CustomStore<number>
}

type CustomStore<T> = {
    value: T,
    init: (value: T) => void;
    set: (value: T) => void;
}

班级LiveStoragedefaultStorage个(第一类IStorage)和storage个(第二类):

class LiveStorage<D = { [key: string]: any }, S = { [key: string]: CustomStore<any> }> {

    private defaultStorage: D
    storage: S

    constructor(defaultStorage: D) {
        this.defaultStorage = defaultStorage as D
        this.storage = {} as S
    }
}

创建实例时,key同时具有这两种类型:

let liveStorage = new LiveStorage<IStorage, IStorage>({})
liveStorage.storage.key // boolean | CustomStore<boolean>

有没有办法让key默认只有CustomStore<boolean>?具有单一接口,并且没有(liveStorage.storage.key as CustomStore<boolean>).我知道那只是编译时间,每次都想从没有(x as type)的IDE那里得到建议.

推荐答案

从本质上讲,您希望defaultStorage是"基本"键值类型,然后希望storage是该类型的transformed版本.对于基本类型T的每个属性键K,您希望获取属性值类型T[K]并将其映射到CustomStore<T[K]>.所以我们可以定义一个这样做的100:

type CustomStorageFor<T> =
    { [K in keyof T]: CustomStore<T[K]> };

在您的示例中,您可能不想直接使用IStorage类型,它有unions个基属性和映射属性.相反,您可以将IStorage定义为基本类型

interface IStorage {
    key: boolean
    key2: number
}

然后通过映射获得CustomStorage版本:

type CustomStorageForIStorage = CustomStorageFor<IStorage>;
/* type CustomStorageForIStorage = {
    key: CustomStore<boolean>;
    key2: CustomStore<number>;
} */

现在,仅在基本类型T中,LiveStorage类就可以是generic,而storage将被赋予类型CustomStorageFor<T>:

class LiveStorage<T extends object> {

    private defaultStorage: T
    storage: CustomStorageFor<T>;

    constructor(defaultStorage: T) {
        this.defaultStorage = defaultStorage
        this.storage = {} as CustomStorageFor<T>; // you need to implement this
    }
}

现在,当您调用LiveStorage构造函数时,编译器将推断类型参数T是构造函数参数的类型参数(我从constrainedTthe object type,因此,如果您试图传入string或更多值,则会得到错误):

const defaultStorage: IStorage = { key: true, key2: 1 };
let liveStorage = new LiveStorage(defaultStorage);
// let liveStorage: LiveStorage<IStorage>
liveStorage.storage.key // CustomStore<boolean>

事实上,如果您不想给IStorage类型命名,您甚至不需要它;编译器将很高兴地从构造函数参数合成一个等价的对象类型:

let liveStorage = new LiveStorage({ key: true, key2: 1 });
// let liveStorage: LiveStorage<{ key: boolean; key2: number; }>
liveStorage.storage.key // CustomStore<boolean>

无论哪种方式都会奏效.

Playground link to code

Typescript相关问答推荐

React组件数组及其props 的类型定义

有没有办法适当缩小类型?

Angular 过滤器形式基于某些条件的数组控制

找不到带名称的管道''

如何在使用`Next—intl`和`next/link`时导航

带占位符的模板文字类型何时扩展另一个?

如何使用Zod使一个基于其他字段值的字段为必填字段?

TypeScrip-将<;A、B、C和>之一转换为联合A|B|C

具有自引用属性的接口

@TANSTACK/REACT-QUERY中发生Mutations 后的数据刷新问题

TypeScrip错误:为循环中的对象属性赋值

使用泛型识别对象值类型

避免混淆两种不同的ID类型

如何从JWT Reaction中提取特定值

仅当类型为联合类型时映射属性类型

如何处理可能为空的变量...我知道这不是Null?

替换typescript错误;X类型的表达式可以';t用于索引类型Y;带有未定义

Typescript泛型-键入对象时保持推理

如何将 MUI 主题对象的自定义属性与情感样式组件中的自定义props 一起使用?

如何确定剧作家中给定定位器的值?