bounty还有3天到期。回答此问题可获得+200声望奖励。Lance正在寻找典型答案:
我不知道为什么我的注入不起作用,在我的HaltList
接口上进行类型检查。正在寻找一个解决方案,以便我可以从库外部对该接口进行类型检查。
我以前做过几次,我知道这就是样式化组件“主题”的工作方式,你可以定义自己的主题属性,它会在样式化组件内部自动完成这些属性。你基本上是这样做的:
import { MyTheme } from '~/configurations'
declare module 'styled-components' {
interface DefaultTheme extends MyTheme {}
}
在./configurations/index.ts
中,我们有:
const theme = {
fonts: {
font1: 'foo'
},
colors: {
red: 'bar'
}
}
export type MyTheme = typeof theme
这个DefaultTheme
正在被我的主题从外部动态扩展。所以样式化组件库中的所有内容都可以根据我的主题进行键入。
那么,当我尝试从头开始实现这个功能时,为什么它不起作用呢?
下面是我所做的,我创建了一个TypeScript library,它是1个文件,像这样:
import { CustomError } from 'ts-custom-error'
export class Halt extends CustomError {
form: keyof HaltList
link: HaltLink
static list: HaltList = {}
// make your codes cool.
static code: (code: number) => string = (code: number) =>
code.toString(16).padStart(4, '0').toUpperCase()
// your template for rendering codes.
static make: (code: string, note: string) => string = (
code: string,
note: string,
) => `[${code}] ${note}`
constructor(form: keyof HaltList, link: HaltLink = {}) {
if (!(form in Halt.list)) {
throw new Error(`Name ${form} missing from halt list`)
}
const hook = Halt.list[form]
if (!hook) {
throw new Error(`Hook ${form} is missing from halt list`)
}
const note =
typeof hook.note === 'function' ? hook.note(link) : hook.note
const code = Halt.code(hook.code)
const text = Halt.make(code, note)
super(text)
Object.defineProperty(this, 'form', {
enumerable: false,
value: form,
})
Object.defineProperty(this, 'link', {
enumerable: false,
value: link,
})
this.form = form
this.link = link
Object.defineProperty(this, 'name', { value: 'Halt' })
}
toJSON() {
const hook = Halt.list[this.form]
if (!hook) {
throw new Error()
}
const note =
typeof hook.note === 'function' ? hook.note(this.link) : hook.note
const code = Halt.code(hook.code)
const term = hook.term
return { code, note, term }
}
}
export type HaltHook = {
code: number
hint?: string | ((link: HaltLink) => string)
note: string | ((link: HaltLink) => string)
term?: Array<string> | ((link: HaltLink) => Array<string>)
}
export type HaltLink = Record<string, unknown>
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export interface HaltList {
[key: string]: HaltHook
}
export function assertHalt(x: unknown): asserts x is Halt {
if (!isHalt(x)) {
throw new Error('Error is not a halt. ' + (x as Error).message)
}
}
export function isHalt(x: unknown): x is Halt {
return x instanceof Halt
}
export default function halt(
form: keyof HaltList,
link: HaltLink = {},
) {
throw new Halt(form, link)
}
在这里,我有HaltList
,我想动态注入属性,所以当我这样做的时候,我得到了TypeScript的代码完成:
halt('
它应该显示我在自定义代码中定义的属性,可能看起来像这样(在./configurations/errors
中):
import { Halt } from '@lancejpollard/halt.js'
const HALT = {
missing_property: {
code: 1,
note: 'Property missing',
},
}
export type HaltType = typeof HALT
Halt.list = HALT
然后我尝试像这样注入它,在我的项目的基础上使用一个test.d.ts
文件:
import { HaltType } from './configurations/errors'
declare module '@lancejpollard/halt.js' {
export interface HaltList extends HaltType {}
}
然而,它似乎并没有做任何事情。我怎么才能得到这个,以便HaltList
现在有我的missing_property
,所以当我执行halt('
时,它会自动完成missing_property
(如果你尝试使用扩展接口中没有定义的东西,它会抛出错误)?
更新
我的用法是这样的:
import { Halt } from '@lancejpollard/halt.js'
const HALT = {
invalid_form: {
code: 3,
note: ({ name }) => `Form '${name}' is not valid`,
},
invalid_type: {
code: 2,
note: ({ name, type }) => `Value '${name}' is not '${type}' type`,
},
missing_property: {
code: 1,
note: ({ name }) => `Property '${name}' missing`,
},
}
export { Halt }
export type HaltType = typeof HALT
Halt.list = HALT
然后在另一个文件中:
throw new Halt('missing_property')
// or
halt('missing_property')
这在halt('missing_
的自动完成方面起作用),但它在Halt.list = HALT
抛出一个错误,说:
Type '{ invalid_form: { code: number; host: string; note: ({ name }: { name: any; }) => string; }; invalid_type: { code: number; host: string; note: ({ name, type }: { name: any; type: any; }) => string; }; missing_property: { code: number; host: string; note: ({ name }: { ...; }) => string; }; }' is not assignable to type 'HaltList'.
Property 'invalid_form' is incompatible with index signature.
Type '{ code: number; host: string; note: ({ name }: { name: any; }) => string; }' is not assignable to type 'HaltHook'.
Types of property 'note' are incompatible.
Type '({ name }: { name: any; }) => string' is not assignable to type 'string | ((link: HaltLink) => string)'.
Type '({ name }: { name: any; }) => string' is not assignable to type '(link: HaltLink) => string'.
Types of parameters '__0' and 'link' are incompatible.
Property 'name' is missing in type 'HaltLink' but required in type '{ name: any; }'.
所以我试着这样做:
import { Halt, HaltList } from "@lancejpollard/halt.js";
const HALT: HaltList = {
// ... rest
现在自动完成功能中断并说:
“string”类型的参数不能分配给“never”类型的参数。
位于halt('missing_property')
的位置。
1条答案
按热度按时间li9yvcax1#
通过键入
你可以确保类型合并 * 确实有效 *(如果不是,写在注解中)
你的问题是你不能只得到
keyof (Record<string, V> & { k: V1 })
,因为你只得到string
要得到你想要的
keyof
,而不是keyof
,你需要删除索引签名:https://tsplay.dev/Nr93zw