【问题标题】:TypeScript: Infer type of object of generic interface implicitly from object contentTypeScript:从对象内容隐式推断通用接口对象的类型
【发布时间】:2021-04-27 20:33:50
【问题描述】:

我在 TypeScript 中有一个简单的案例,其中我有一个带有泛型类型 T 的接口,它扩展了一个枚举 E。根据类型分配配置类型。

enum E { "A", "B" }

type ConfigsBase = { [K in E]: object }

interface Configs extends ConfigsBase {
    [E.A]: { a: string };
    [E.B]: { b: number };
}

interface MyInterface<T extends E> {
  type: T;
  config: Configs[T];
}

问题是我如何以从对象隐式推断出泛型类型的方式使用此接口。这样当配置错误时我会得到有用的类型错误。

const a: ??? = {
  type: E.A,
  config: { a: 1 }, 
}
// => I want this to give a typescript error because 1 is not a string

我需要为??? 插入什么,以便打字稿给出配置错误的错误。它应该类似于const a: MyInterface&lt;look for yourself what T is&gt;

我通过使用自动推断类型的标识函数找到了一个相对繁琐的解决方案:

const inferType = <T extends E>(obj: MyInterface<T>): MyInterface<T> => obj

const a = inferType({
  type: E.A,
  config: { a: 1 },
})

// => TypeScript error: Type 'number' is not assignable to type 'string' 

是否可以在不使用函数的情况下通过类型注释更优雅地做到这一点?

【问题讨论】:

标签: typescript typescript-generics


【解决方案1】:

infer 运算符有一种方法。见https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-inference-in-conditional-types

你可以这样做:

enum E { "A", "B" }

type ConfigsBase = { [K in E]: object }

interface Configs extends ConfigsBase {
    [E.A]: { a: number };
    [E.B]: { b: number };
}

interface MyInterface<T extends E> {
  type: T;
  config: Configs[T];
}

type InferType<obj> = obj extends MyInterface<infer R> ? MyInterface<R> : never;

const variable = {
    type: E.A,
    config: { a: 1 }
};

const inferredVariable: InferType<typeof variable> = variable;

会更快,因为你不使用函数。

Updated Playground

【讨论】:

  • 哈哈,谢谢!这是函数选项的一个很好的替代方案。
  • 但是,在这种情况下,错误消息会更糟(如果您留下原始类型[E.A]: { a: string };):Type '{ type: E; config: { a: number; }; }' is not assignable to type 'never'.
  • 是的,这将永远不会生成,因此将显示更糟糕的错误描述。 @erksch,请接受我的问题
【解决方案2】:

在 kotlin 中你会使用密封类:

sealed class Config {
    data class ConfigA(val a: String): Config()
    data class ConfigB(val b: Int): Config()
}

val a = Config.ConfigA(1)//type error here

fun main() {
    val c : Config = a

    when (c) {// no type property needed
        is Config.ConfigA -> c.a
        is Config.ConfigB -> c.b
    }
}

【讨论】:

  • 问题是关于 TypeScript,而不是 Kotlin。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-09
  • 1970-01-01
  • 2018-09-19
  • 2020-09-02
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
相关资源
最近更新 更多