[TypeScript] TransformCallback's Result argument as non-optional
See original GitHub issueHello there!
I noticed that the TransformCallback
(return value from postcss.plugin()
) in the type definitions receives an optional result
argument.
I cannot think of a reason why result
would be undefined. But leaving its type this way forces my plugin to deal with the possibility. I have to add an ugly block of code near the top of my transform callback that looks like this, just so that that I don’t have to check for undefined
later:
if (result === undefined) {
throw new Error('Cannot run without a result defined');
}
I propose that we change the definition to the following:
interface TransformCallback {
/**
* @returns Asynchronous plugins should return a promise.
*/
(root: Root, result: Result): Promise<any> | any;
}
This should not break existing TypeScript implementations since a function which doesn’t use the result
argument would still implement this interface. You’ll also notice that the return value is changed, which also shouldn’t break anything, since both the existing return type and the one I’ve proposed uses a union with any
, which is effectively still any
. I just think this reads clearer, since asynchronous plugins should return a Promise, and otherwise the return value doesn’t really matter.
If this sounds good to the maintainers, I’m happy to make the PR.
cc @jedmao (seems to be the resident typescript expert)
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:5 (5 by maintainers)
Hmm… I guess the meaning of
any
in this situation is subjective. It’s totally valid that you feel it could mislead the developer into thinking the value has meaning, and yet it’s also totally valid that I thinkvoid
could signal that it’s significant that there’s no value returned, hence TypeScript exhibiting the behavior thatnumber
is not assignable tovoid
.I’d like you to consider an example, which is actually the situation for the plugin I’m writing. I return a function that can call itself. When it calls itself, it’s return value is important, and I chose that it returns a
Promise<Container>
. I use theContainer
value to recursively merge declarations back up to theRoot
. This isn’t really an edge case, as any plugin dealing with importing or processing nested structures would likely design them to do the same. From an implementation point of view, this works. However if the return type ofTransformCallback
wasPromise<void>
, I would need to do something like the following just to satisfy the type system:I’d have to effectively erase the resolved value of my recursive function so that it’s resolved value is assignable to
void
. That seems just as bad (actually worse, there’s a performance cost) than thethrow
I used to convince the type system thatresult
is never undefined. This demonstrates my interpretation above: TypeScript saysContainer
is not assignable tovoid
, so I must interpret the return type ofvoid
as meaningful.How do you feel about keeping it as I’ve suggested, but in order to clarify the subjective interpretation, we add to the doc comments to explicitly let the user know
any
is being used to stand in for a value that will be ignored.Recursion is a great example of the need for a more loose type.