我正在尝试定义一个与任何对象/字典匹配但不与数组匹配的类型。
我的第一次尝试没有用,因为从技术上讲,数组是底层的对象:
const a:{[k:string]: any} = []; // works fine
我也知道,可以像这样创建通用的“检查器”:
type NoArray<T> = T extends any[] ? never : T;
但这不是我想要的。我想要这样的非泛型类型:
const a: NoArrayType = {}; // works fine
const a: NoArrayType = []; // TypeError
答案 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
出于相同的原因,您可以执行以下操作,因为any
是打字稿始终允许您将值强制转换为这种情况的一种情况。
const a: any = true
const b: any = {}
const c: any = new AnyClass()
所以您有一些选择。
any
。如果您知道这些属性上可能的值,请声明它们。interface MyObjectType { [k: string]: number | string }
const a: MyObjectType = [] // fails
const b: MyObjectType = {} // works
也许这是JSON
?如果是这样,any
是不正确的类型,因为您知道它不可能包含某些东西(例如类实例或函数)。
interface Json {
[key: string]: string | number | boolean | Json | Json[]
}
const a: Json = [] // type error
const b: Json = {} // works
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
}
答案 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 数组。也许这有点帮助:)