匹配任何对象但不匹配数组的TypeScript类型

时间:2020-04-10 20:48:47

标签: typescript

我正在尝试定义一个与任何对象/字典匹配但不与数组匹配的类型。

我的第一次尝试没有用,因为从技术上讲,数组是底层的对象:

const a:{[k:string]: any} = []; // works fine

我也知道,可以像这样创建通用的“检查器”:

type NoArray<T> = T extends any[] ? never : T;

但这不是我想要的。我想要这样的非泛型类型:

const a: NoArrayType = {}; // works fine
const a: NoArrayType = []; // TypeError

2 个答案:

答案 0 :(得分:3)

类型问题是类型声明中的any。在大多数打字稿应用程序中通常都希望避免使用any

数组只是可以用数字键索引的对象,并具有一些其他方法。实际上,您几乎可以为该类型分配任何非原始值。

const a: {[k:string]: any} = [1,2,3]; // works
const b: {[k:string]: any} = {a: 123}; // works
const c: {[k:string]: any} = () => { console.log(123) }; // works
const d: {[k:string]: any} = () => new AnyClass(); // works

Playground

出于相同的原因,您可以执行以下操作,因为any是打字稿始终允许您将值强制转换为这种情况的一种情况。

const a: any = true
const b: any = {}
const c: any = new AnyClass()

Playground

所以您有一些选择。

  1. 限制您的类型,以免您强制转换为any。如果您知道这些属性上可能的值,请声明它们。
interface MyObjectType { [k: string]: number | string }
const a: MyObjectType = [] // fails
const b: MyObjectType = {} // works

Playground

也许这是JSON?如果是这样,any是不正确的类型,因为您知道它不可能包含某些东西(例如类实例或函数)。

interface Json {
  [key: string]: string | number | boolean | Json | Json[]
}

const a: Json = [] // type error
const b: Json = {} // works

Playground

  1. 或者使用unknown类型代替any,这要求您在使用值之前在运行时检查类型。
interface MyObjectType { [k: string]: unknown }

const a: MyObjectType = [] // type error
const b: MyObjectType = { prop: 123 } // works

// b.prop type here is: unknown
b.prop.toUpperCase() // type error

if (typeof b.prop === 'string') {
  // a.prop type here is: string
  console.log(b.prop.toUpperCase()) // works
}

Playground

答案 1 :(得分:1)

这似乎可以满足您的需求:

type NonArrayObject = {
    [x: string]: any
    [y: number]: never
}

let p: NonArrayObject = {}             // fine
let q: NonArrayObject = { foo: "bar" } // fine
let r: NonArrayObject = []             // type error
let s: NonArrayObject = ["foo", 3]     // type error

编辑:空数组的类型错误似乎是本地人为造成的。在 playground 中,它似乎只能阻止 populated 数组。也许这有点帮助:)