Reputation: 2207
I seem unable to understand why I cannot use custom type inside an interface.
I have the following definition:
type Operation = 'update'|'remove'|'add'
interface Rule {
op: Operation
path:string
value?:any
}
function applyDiff<Output>(rules: Rule[], obj: object): Output;
but I receive Type 'string' is not assignable to type 'Operation'
as an error at this failing test:
const obj = {a: {b:1, c:2}}
const rules = [
{op: 'update', path: 'a.c', value:10},
]
const result = applyDiff(rules, obj)
but this code works just fine:
function fn(x: number, y: 'add'|'remove'|'update'){
return x > 1 && y === 'add'
}
const result = fn(1, 'remove')
What I am missing here? I would appreciate any helpful guidance on the matter. Thank you.
Upvotes: 1
Views: 67
Reputation: 122116
First, the simple solution:
const rules: Rule[] = [
// ^------^
{op: 'update', path: 'a.c', value:10},
]
But why doesn't that work to begin with? Because the inferred type of rules
is {op: string; path: string; value: number}[]
, and there are lots of string
s that aren't any of the values in the Operation
union. Objects and arrays are mutable, so there's nothing to prevent the value of op
changing (e.g. pushing a new object into the array, or mutating the existing object in the array) between defining rules
and passing it to applyDiff
.
This also suggests some other solutions:
Pass the array directly to the function:
const result = applyDiff([
{op: 'update', path: 'a.c', value:10},
], obj);
Here there's no way for the values to change between defining the array and passing it to applyDiff
, so the narrower type {op: 'update'; path: 'a.c'; value: 10}[]
is inferred.
Use a const
assertion to explicitly narrow the type of the rule:
const rules = [
{op: 'update', path: 'a.c', value:10} as const,
// ^-------^
];
This tells the compiler you consider that object to be immutable, which leads it to infer a narrower type for rules
too. You could instead explicitly narrow the type of the op
:
const rules = [
{op: 'update' as const, path: 'a.c', value:10},
// ^-------^
];
with similar effects.
Upvotes: 1