1

我正在寻找一个 TypeScript 类型定义,它描述具有单个属性(具有任何值)的对象。

我知道这是索引签名,例如

type X = { [key: string]: any }

或者

type X = Record<string, any>

但是,这将允许像

const obj: X = {
  "a": 12,
  "b": "c"
}

我正在寻找一种 Y 类型,它限制 obj 具有单个属性,代表一种“RecordEntry”,即

const obj: Y = {
  "a": 12
}

应该没问题但是

const obj: Y = {
  "a": 12,
  "b": "c"
}

应该被编译器拒绝。

这甚至可能吗?

4

2 回答 2

0

我认为这是不可能的,这是我能想到的最好的方法:

type NotUnion<T, U = T> =
  T extends any ?
    [U] extends [T] ? T
    : never
  : never;

type SingleProperty<T extends {}> =
  keyof T extends NotUnion<keyof T> ? T
  : never;

const oneProperty = {
  a: 'a'
};
const onePropertyAgain: SingleProperty<typeof oneProperty> = oneProperty; // works

const twoProperties = {
  a: 'a',
  b: 'b'
};
const twoPropertiesAgain: SingleProperty<typeof twoProperties> = twoProperties; // compiler error

你可以像这样使它更好一点:

function asSinglePropertyObject<T extends {}>(obj: SingleProperty<T>): SingleProperty<T> {
    return obj;
}

const oneProperty = asSinglePropertyObject({
    a: 1 // works
});

const twoProperties = asSinglePropertyObject({
    a: 1, // Type 'number' is not assignable to type 'never'
    b: 'a'
});
于 2020-04-09T11:30:31.480 回答
0

听起来你想要的只是

type RecordEntry<T> = Record<string, T>

我不相信有办法限制只有一种未指定的类型。这种事情的语义也可能令人困惑。例如,如果你有

class A {}

class B extends A {}

const obj: RecordEntry = { a: new A(), b: new B() };

那会是编译器错误吗?

于 2020-04-09T02:57:37.980 回答