我试图将我的
styled-component
mixin 模块转换为打字稿,但遇到了一个我无法解决的问题(在 chain
方法中)。现场游乐场这里。
// Sample mixin methods
const fullscreen = () => `
width: 100vw;
height: 100vh;
`
const squared = (size: string) => `
width: ${size};
height: ${size};
`
interface mixinInterface {
fullscreen: typeof fullscreen
squared: typeof squared
}
type chainedMixinInterface = {
[P in keyof mixinInterface]: (...args: Parameters<mixinInterface[P]>) => () => string
}
const mixins: mixinInterface & { chain: () => chainedMixinInterface } = {
fullscreen,
squared,
// ...other mixin methods
chain: function () {
const chainedObject: Partial<chainedMixinInterface> = {}
let accumulatedReturn = ''
// get mixin keys without 'chain'
const keys = Object.keys(mixins).filter(key => key !== 'chain') as (keyof mixinInterface)[]
keys.forEach(key => {
const mixinFunction = mixins[key]
// wraps subsequent mixin methods
chainedObject[key] = function (...args: Parameters<typeof mixinFunction>) {
accumulatedReturn += mixinFunction(...args) // Error: A spread argument must either have a tuple type or be passed to a rest parameter.
const returnAllChainedValues = () => accumulatedReturn
return Object.assign(returnAllChainedValues, this) // pass along the methods to be chained
}
})
return chainedObject as chainedMixinInterface
}
}
这是链的用例:
const Div = styled.div`
// returns a function that returns the chained results
// which will be called by styled-component's tag function
${mixins
.chain()
.fullscreen()
.squared('50px')
// ...other mixin methods
}
`
通过调用
chain
函数,它包装了对 mixin 方法的后续调用。它不返回字符串,而是返回一个函数,该函数返回所有链接方法的累积结果(字符串)。
尽管我将
...args
指定为当前正在迭代的 mixinFunction
的参数,但它不是一个元组,而是元组的并集。因此,TypeScript 在以下行中抛出错误,我在 args
调用中展开了 mixinFunction
。
我还没有找到解决这个问题的方法。有没有办法通过仅修改类型而不更改底层 JavaScript 来回避这个问题?
TypeScript 不会根据具体情况进行类型缩小,仅针对泛型类型。考虑下面的代码
interface MyType {
n: number,
s: string
}
function selfAssign(a: MyType, key: keyof MyType) {
// Error:
// Type 'string | number' is not assignable to type 'never'.
// Type 'string' is not assignable to type 'never'.
a[key] = a[key]
}
selfAssign({ n: 3, s: 'abc'}, 'n');
尽管
a[key] = a[key]
显然是类型安全的,但 TS 没有表示“[key] 的类型,无论它是什么”的类型。
据 TS 所知,您正在尝试将一个可能是数字或字符串的值分配给仅接受数字或仅接受字符串的属性。
它表示左边的
a[key]
是“never”类型,因为没有值可以同时满足数字和字符串。在稍微不同的情况下,错误会有所不同,但原理是相同的。
在您的情况下,
mixinFunction
可以是每个具有不同签名的几个函数之一,因此 Parameters<typeof mixinFunction> is the intersection of all those possibilities. Therefore, I believe it's not possible to generically
...argsto
mixinFunction`。您要么必须以允许 TS 识别类型匹配的方式更改底层 JS 代码,要么放宽类型安全性。例如
accumulatedReturn += (mixinFunction as unknown as (...args: any) => () => string)(...args)