generics - Starkaste sättet att göra nominella typer i Typescript?
Jag har sett många olika sätt att göra nominella typer i Typescript, men de verkar alla brista på något sätt. Jag skulle vilja att alla dessa egenskaper gäller:
- Måste ha tydliga (inte nödvändigtvis kortfattade, men bonuspoäng om så) kompilatorfelmeddelanden som kommunicerar vilka opaka typer, t.ex.
Type 'GBP' går inte att tilldela typen 'JPY'. - Måste vara verkligen unik för att undvika att av misstag matcha liknande opaka typer, dvs. inga
__tag__-nycklar, måste användaunique symbol. - Måste kunna ha säkra generiska funktioner som tar opaka typer med samma underliggande primitiva typ, t.ex.
<A>(Opaque<number, A>) => Opaque<number, A>.
Fler bonuspoäng för ett syntaktiskt rent gränssnitt, men jag förstår att det är subjektivt.
Svar #1
Det här är det bästa tillvägagångssättet jag har upptäckt:
namespace Unique {
export declare const Newtype: unique symbol
export declare const JPY: unique symbol
export declare const GBP: unique symbol
}
type Newtype<A, B extends symbol> = A & { readonly [Unique.Newtype]: B }
type JPY = Newtype<number, typeof Unique.JPY>
type GBP = Newtype<number, typeof Unique.GBP>
const test: <A extends symbol>(a: Newtype<number, A>, b: Newtype<number, A>) => Newtype<number, A>
= (a, b) => a + b as any // massage the type checker a bit
// fails
test(10 as GBP, 10)
test(10 as GBP, 10 as JPY)
// passes
test(10 as GBP, 10 as GBP)
test(10 as JPY, 10 as JPY)
håller, men inga bonuspoäng här eftersom du slutar med några riktigt obehagliga felmeddelanden som innehåller sökvägar till filer (levande exempel, se "Fel"):
Newtype<number, typeof import("file:///input").JPY>. Jag hoppas att det finns ett sätt som involverar interface extends eller liknande för att göra detta renare.gäller eftersom både
Unique.NewtypeochUnique.JPYärunique symbol.håller eftersom vi kan använda strukturen av
Newtypeför att säkerställa att typerna definitivt ärNewtype, på grund av att det är definierat i termer avUnique.Newtypesom ärunik symbol.
