“作为常量”与类型相结合?

use*_*768 9 types constants literals typescript typesafe

我想将具有常量类型的两者结合起来,并使用它“作为常量”来获取文字类型作为类型:

type MyType = {name: string};

const x:MyType = {
    name: 'test' // Autocompleted, typesafe. But Type is {name: string}, not 
                 // what I want, {name: 'test'}
}

const x = { name: 'test' } as const; // Gives correct type, but no type check...
Run Code Online (Sandbox Code Playgroud)

这该怎么做?

Tom*_*rez 52

2022 年 9 月编辑:

在 Typescript 4.9 中,我们现在可以使用satisfies运算符:

type MyType = { name: string }

const x ={
  name: 'test', // Autocompleted, typesafe
} as const satisfies MyType

x.name // type is 'test' (not string)
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因,您无法使用satisfies,则复制相同的行为相当容易:

/**
 * Replacement for TS satisfies operator, until it's well supported
 * Usage:
 * const test = satisfy<{ a: string }>()({ a: 'test', b: 'test' })
 * */
export function satisfy<TSatisfied>(): <T extends TSatisfied>(value: T) => T {
  return (value) => value
}
Run Code Online (Sandbox Code Playgroud)

以前的解决方案:

这是实现您想要的目标的一种方法:

type MyType = { name: string }

// This function does nothing. It just helps with typing
const makeMyType = <T extends MyType>(o: T) => o

const x = makeMyType({
  name: 'test', // Autocompleted, typesafe
} as const)

x.name // type is 'test' (not string)
Run Code Online (Sandbox Code Playgroud)


Sha*_*son 1

不需要类型检查,{name: "test"} as const因为 Typescript 使用结构相等的含义,只要{name: "test"} as constMyType 的结构相同,它们就相等,因此是相同的。

使用这些辅助类型可以观察到此行为。

interface MyType {
     name: string;
}
const test = {name: "test"} as const;
type IsEqual<T, U> = [T] extends [U] ? true : false;
type AreTheyEqual = IsEqual<typeof test, MyType> // true they are the same.
Run Code Online (Sandbox Code Playgroud)

任何采用 MyType 的东西都可以采用 typeof Test。

编辑:如果您想强制测试为 MyType 类型以进行类型检查测试,则不能通过保留字符串文字来做到这一点,因为任何断言为 MyType 的内容都会丢失文字类型并回退到字符串,可以在此处观察到此行为。

type MyType = {name: string};
const x:MyType = {
    name: 'test' as const
}
type Test = typeof x["name"] // string;
Run Code Online (Sandbox Code Playgroud)

这意味着如果您想在 MyType 上同时拥有文字和字符串类型,您将需要执行类似的操作(更改 MyType)。请注意,使用它似乎很冗长,但可以说比“as const”更少样板

interface MyType<NAME extends string = string> {
    name: NAME;
}
const x: MyType = {
    name: 'test' // string;
}
const y: MyType<"test"> = {
    name: "test" // "test"
}

type Test1 = typeof x["name"]// string;
type Test = typeof y["name"] // "test";
Run Code Online (Sandbox Code Playgroud)

^ 允许字符串和文字类型。

  • 它们确实是相等的,唯一的问题是当我键入时,我想键入检查我在 const test 中键入的内容是否确实满足 MyType。使用 as const 时,没有这样的限制,所以我输入它是不安全的。但我可以在完成输入后切换... (3认同)