3 ms·
Why? why make your code so complex you even hit this problem. Just use the type: const x: Thetype = .... I am not keen on as const either. Just program to int
by nrhrjrjrjtntbt 11mo ago
Why? why make your code so complex you even hit this problem. Just use the type:
const x: Thetype = ....
I am not keen on as const either. Just program to interfaces. It is a better way to think IMO.
- ibejoeb 11mo agoThe author gets into that. `Thetype` might be complex. It also protects you from overgeneralizing, like casting to and from `unknown` to escape the type checker. type Current = { kind: "ac" | "dc"; amps: number; } type Dc = { kind: "dc"; amps: number; } const ac: Current = { kind: "ac", amps: 10000000, } const handleDc = (thing: Dc) => {} const badConvert = (c: Current) => ({...c, kind: "dc"}); /** * Argument of type '{ kind: string; amps: number; }' is not assignable to parameter of type 'Dc'. Types of property 'kind' are incompatible. Type 'string' is not assignable to type '"dc"'.(2345) */ handleDc(badConvert(ac)); const goodConvert = (c: Current) => ({ ...c, kind: "dc", } satisfies Dc); handleDc(goodConvert(ac)); /** * Object literal may only specify known properties, and 'bar' does not exist in type 'Dc'. */ const badConvert2 = (c: Current) => ({ ...c, kind: "dc", bar: "qwerty" } satisfies Dc);
- nrhrjrjrjtntbt 11mo agoI see. I dont mind this use case as much. It is like a hint.
- ibejoeb 11mo agoExactly. It's a safer assertion, as the author points out. You can work without it, but it's a little more cumbersome and involves creating the otherwise unnecessary, transient intermediate types.
- another_twist 11mo agoThe bad convert is actually wrong. It should be refactored to an equality check and throw an error if account kind is not "dc". The compiler is correct and its not a good idea to work around this issue.
- MrJohz 11mo agoNo, the point of the function is to convert the type. It doesn't need to check anything, it just forcibly converts any argument to DC. The compiler isn't complaining because the conversion isn't valid, it's complaining because it doesn't know that the string "dc" should be narrowed down to a literal type, and so it's kept it as broad as possible. Using `satisfies` lets it understand that it needs to do narrowing here. In fairness I don't think this is the best case for `satisfies`, and some return type annotations would probably work a lot better here, and be clearer to read.
- ibejoeb 11mo agoAbsolutely. It's contrived example. If you control the API, you'd be better to rewrite it: type Current = { amps: number; }; type Ac = { kind: "ac" } & Current; type Dc = { kind: "dc" } & current; const currentToDc = (c: Current): Dc => ... const acToDc = (c: Ac): Dc => ... And it would flow more naturally. Or define a CurrentKind and include it in current if you don't need to handle the scalar. There are plenty of better ways. That's also something that you can become accustomed to and recognize when you have a weak API. I'm not really trying to make a case for `satifies`, but it can be handy and clean in some circumstances, especially when you're constrained by a third-party API.
- halapro 11mo agoBecause what you wrote broadens the type. `satisfies` validates the type without broadening it. const c: string = 'c'; This will be of type string instead of type 'c'. This is a barebones example and it already breaks support for template literal types. Imagine how much better `satisfies` is for complex union types.