检查类型而不推断检查类型

时间:2019-10-17 16:55:34

标签: typescript

考虑以下类型

interface ISmth<T> {
  id: number;
  data: T;
}

现在我要声明一个包含此类项目的数组

var a = [{
  id: 1,
  data: [],
}, {
  id: 2,
  data: 4,
}, {
  id: 3,
  data: "abc",
}] as const

我想使用as const,因为此数组将永远不会更改,并且它包含我想区分的data属性的不同类型。

但是同时我希望打字稿确保每个数组元素都由ISmth<any>表示。我该如何表达这种确认?

2 个答案:

答案 0 :(得分:1)

Here is it

interface ISmth<T> {
  id: number;
  data: T;
}

var a = [{
  id: 1,
  data: [],
}, {
  id: 2,
  data: 4,
}, {
  id: 3,
  data: "abc",
}] as const

type T = (typeof a extends Readonly<ISmth<any>[]> ? Object : never);
interface X extends T { }

因此,如果满足条件,T代表Object并进行代码编译。
否则Tnever,接口无法扩展never并产生错误。

答案 1 :(得分:1)

a上强制类型约束的两种方法:

仅编译时键入断言

这是@Qwertiy提出的解决方案,它在失败的类型断言情况下使用扩展never类型的接口来强制执行编译错误。另外,还可以借助generic type constraint触发编译错误。如果我们允许断言类型为通用类型并接收任意多个类型,则可以这样写(Playground):

type AssertAssignable<T, U extends T> = true

var a = [{
    id: 1,
    data: [],
}] as const

var aError = [{
    id: "foo",
    data: [],
}] as const

type Assert = AssertAssignable<readonly ISmth<any>[], typeof a> 
type AssertError = AssertAssignable<readonly ISmth<any>[], typeof aError> // error(OK!)

涉及辅助函数的类型断言(出于完整性考虑,已从here移出)

可以定义一个辅助函数createA,其唯一目的是在a的已创建对象文字上声明类型,同时仍通过as const({{3 }}):

function createA<A extends Readonly<ISmth<any>[]>>(a: A): A {
    return a
}

var a = createA([{
    id: 1,
    data: []
}] as const);

var aError = createA([{
    id: "1", // error (OK!)
    data: []
}] as const);

如果createA未被重用,您甚至可以使用Playground内联声明:

var aInline = (<A extends Readonly<ISmth<any>[]>>(a: A) => a)([{
    id: 1,
    data: [],
}] as const)

...或定义通用的可导出实用程序帮助器。

function enforceTypedLiteral<T>() {
    return <A extends T>(a: A) => a
}

enforceTypedLiteral<readonly ISmth<any>[]
>()([{
    id: 1,
    data: []
}] as const)