我正在尝试创建基于键定义值的类型。如果键扩展$${string}
(例如$foo
),则值应为不带前缀的键,例如foo
。如果键不扩展$${string}
(例如boo
),则值应为null
。
- 示例**
const example = {
$foo: 'foo',
boo: null,
}
下面是我创建的一个独立的示例-但是当我将其应用到下面的代码中时,它并没有按预期工作。😕
type Value<T> = T extends `$${infer I}` ? I : null
type ExampleA = Value<'$foo'> // type is 'foo'
type ExampleB = Value<'boo'> // type is null
- 我的当前代码**
type Values = {
[K in string]: K extends `$${infer p}` ? p : null;
}
const values = {
$foo: 'foo', // Type 'string' is not assignable to type 'null'.
foo: null,
$boo: 'boo', // Type 'string' is not assignable to type 'null'.
boo: null,
} satisfies Values;
type Expected = {
readonly $foo: 'foo',
readonly foo: null,
readonly $boo: 'boo',
readonly boo: null,
}
satisfies Values
用于稍后推断类型。类似的方法是可接受的🙂
谢谢你的帮助和时间-干杯
1条答案
按热度按时间jjjwad0x1#
Values
类型的问题在于string
上的mapped types没有按照您期望的方式工作。虽然 * 概念上 * 您可以将string
视为所有可能的字符串类型的无限并集,但string
上的Map类型甚至不会尝试迭代所有可能的字符串类型;它只Map了一件事string
:由于
string
不扩展\$${infer S}
,因此string
键的属性类型为null
。正如microsoft/TypeScript#22509中所讨论的,这是按预期工作的。
string
上的Map类型不是您想要的。不幸的是,没有办法在TypeScript中编写一个特定的类型,使其按照您想要的方式工作。
使用模板字符串模式索引签名,但无法表示属性值字符串需要匹配
"$"
字符后的部分(不仅仅是string
)和其他键需要具有null
的部分(不仅仅是string | null
):因此,我们不得不放弃使用
satisfies
操作符的方法,因为没有合适的Values
类型可以使用它。你真正关心的是让编译器推断出
values
的类型,但仍然检查你想要的约束。我们可以通过用generic帮助函数替换satisfies Values
来获得这样的行为,我们可以调用satisfiesValues()
。在运行时,这个函数只返回它的输入,但是编译器可以使用它来验证传入的对象字面值。因此,您可以编写const values = satisfiesValues({...});
而不是const values = {...} satisfies Values;
。下面是一个可能的实现:
该函数在
K
中是泛型的,val
是传入的val
值的键。这很可能是已知键的某种并集(没有一个键只是string
),然后Map的类型按预期的方式运行:看起来不错。
values
的类型是你想要的,编译器允许有效的属性,并抱怨无效的属性。Playground代码链接