TypeScript 建议:使用声明的typeof定义其类型

7cwmlq89  于 2022-10-29  发布在  TypeScript
关注(0)|答案(9)|浏览(456)

检索词

  • 推断变数宣告
  • 声明类型
  • 在当前表达式上使用typeof
  • 将修饰符应用于声明
  • 泛型宣告

建议

我想使用当前声明类型来修改变量类型,我正在创建,例如:

const foo: Readonly<typeof var> = {
  bar: 'baz',
}

也许,还有更好的语法,那是我想不到的。

用例

默认情况下,Typescript从变量声明中推断出相当窄的类型,这是一件好事。有时候我们想扩大它,这样它就可以适合我们的接口。大多数情况下,这可以通过简单地声明某个类型的变量来实现。但有时候,在此过程沿着创建一些对象并以某种方式扩展它的推断类型是有用的(某些库可以导出非常复杂的泛型类型,因此显式地编写它们可能会很麻烦)
我的具体用例是由reselect库引起的,当时我试图重用一些选择器。

// typeof selectors is (selector1ReturnType | selector2ReturnType | selector3ReturnType)[]
const selectors = [
  state => someSelector1(state),
  state => someSelector2(state),
  state => someSelector3(state),
]

但是这个选择器数组不能在createSelector函数中使用,因为它需要一个选择器元组,以正确推断选择器函数的参数类型。我试图在我的声明中使用as const,但是它导致了另一个错误,因为createSelector需要一个可变元组(这只是一个类型问题,并不是说它真的改变了选择器,但我恐怕,这在所有库类型中确实是一个常见的情况,我也发现了a solution可以用函数来创建元组,但是我不喜欢这样的事实,静态类型需要一些(甚至很小的)运行时开销,而且解决方案不是通用的。
现在,我使用this文档中的Writable类型,得到了如下代码:

const selectorsConst = [
  state => someSelector1(state),
  state => someSelector2(state),
  state => someSelector3(state),
] as const
const selectors: Writable<typeof selectorsConst> = selectorsConst as any

但这个解决方案也不太好。我希望它看起来像这样:

const selectorsConst: Writable<typeof var> = [
  state => someSelector1(state),
  state => someSelector2(state),
  state => someSelector3(state),
] as const

或者甚至是类似这样的内容(但这超出了本问题的讨论范围):

const selectorsConst: Tuple<typeof var> = [
  state => someSelector1(state),
  state => someSelector2(state),
  state => someSelector3(state),
]

示例
创建只读、部分、可写等对象:

const foo: Partial<typeof var> = {
  bar: {
    baz: 'value',
  },
}
foo.bar.baz = 'new value' // Error: Object is possibly 'undefined'

统一对象值类型:

interface MyClass {
  bar?: string;
  baz?: string;
}
const foo: {
  [key in keyof typeof var]: MyClass;
} = {
  firstEntry: { bar: 'bar' },
  secondEntry: { baz: 'baz' },
}

检查清单

我的建议符合以下准则:

  • 这不会是对现有TypeScript/JavaScript代码的重大更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不基于表达式的类型发出不同JS的情况下实现
  • 这不是运行时功能(例如,库功能、带有JavaScript输出的非ECMAScript语法等)
  • 这个特性将与TypeScript's Design Goals的其余部分一致。
wztqucjr

wztqucjr1#

我不是100%确定我理解了,但是as const能满足你的需要吗?看起来应该能。(不幸的是,对于数组,as const使用ReadonlyArray,它与Array不兼容)。

bzzcjhmw

bzzcjhmw2#

让我来总结一下,并建议一些替代语法。这是你要找的吗?

interface Pair<T> {
  a: T;
  b: T;
}

// Same as if I had written p: Pair<number>
const p: Pair<infer> = {
  a: 10,
  b: 20
};
mefy6pfw

mefy6pfw3#

我认为它更沿着是

interface Pair<T> {
  a: T;
  b: T;
}

// Same as if I had written p: Pair<{a: number, b: number}>
const p: Pair<infer> = {
  a: 10,
  b: 20
};
col17t5w

col17t5w4#

你能修正你的例子吗?这里有一个错误,我不确定你的意思是哪个方向。

i5desfxk

i5desfxk5#

@瑞安·卡瓦诺在哪里?

c2e8gylq

c2e8gylq6#

它不会真正起作用,会有类型错误,它可能是用于幂等运算的,或者我误解了你的建议

// Same as if I had written p: ReadOnly<{a: number, b: number}>
const p: ReadOnly<infer> = {
  a: 10,
  b: 20
};
mbyulnm0

mbyulnm07#

@RyanCavanaugh我不是这个意思。infer的类型应该是typescript指定给你声明的类型。在你的例子中应该是:

{
  a: number;
  b: number;
}

因此,Pair接口不会接收Tnumber
也许,您可以将示例更改为如下形式:

interface Pair<T> {
  a: T;
  b: T;
}

// Same as if I had written p: Pair<number>
const p: Pair<infer['a']> = {
  a: 10,
  b: 20
};
k4aesqcs

k4aesqcs8#

是的,我认为,主要的情况是对类型进行幂等运算,比如Partial,Readonly,ReturnType等等。也许还有更多的用途。

olqngx59

olqngx599#

我找到了这个建议的另一个用例:

// Use type described here https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html to achieve type parameter inference
type AnyFunction = (...args: any[]) => any
type TargetInterface<T> = {
  field: T, 
  otherField: boolean;
}
type FunctionThatShouldReturnInterface<T extends AnyFunction> = T extends (...args: any[]) => 
TargetInterface<infer R>
  ? () => TargetInterface<R>
  : never

// Use my suggestion here
const getInterface: FunctionThatShouldReturnInterface<infer> = () => ({
  field: someComplexTypeSelector(), // Type, that we don't want to repeat, cause it can be complex
  otherField: true;
})

// Without suggestion, and it can get more complex, if we use more fields
const getInerface2 = (): TargetInterface<ReturnType<typeof someComplexTypeSelector>> => ({
  field: someComplexTypeSelector(), 
  otherField: true;
})

// Same hack, as I described in the main post
const getInerfaceConst = () => ({
  field: someComplexTypeSelector(), 
  otherField: true;
})
export const getInerface3: FunctionThatShouldReturnInterface<typeof getInerfaceConst> = getInerfaceConst
我试图解决的真实的问题是这样的:

1.我有一个React SPA,它使用钩子来加载组件中的数据,这些组件代表不同的页面。
1.我想在应用程序加载器上使用钩子(在主组件中),这样所有页面都可以在后台加载它们数据,
1.数据加载挂接以统一的元组格式返回数据:x1m0n1x
1.我想为这个钩子创建类型,这样它就可以检查用户是否返回了所需的元组,但我不想强迫他写数据的类型,他会显式返回,因为它可以很容易地从函数ReturnType中推断出来。
@RyanCavanaugh也许你可以给予我一些指导,如果你认为,这可以实现没有大的开销,所以我可以做一个公关?我是新的ts代码库,所以任何帮助将不胜感激。

相关问题