adl icon indicating copy to clipboard operation
adl copied to clipboard

TypeScript: newtype generates type alias and not proper newtype

Open bitc opened this issue 4 years ago • 2 comments

Hello it appears that when we use ADL newtype then the TypeScript output is:

type MyNewType = string;

This is not a proper newtype and isn't type safe. TypeScript doesn't have native newtype support but there are various ways to emulate them. (Here is one way: https://github.com/gcanti/newtype-ts)

Thank you

bitc avatar Dec 30 '20 18:12 bitc

I'd definitely like to have a better newtype representation in typescript... but typescript's structural typing makes this hard.

How does newtype-ts work for parameterized types? In many projects, we have an ADL newtype is:

newtype DbKey<T> = String;

which stores a string that is a relational foreign key to a table of type T. Hence DBKey<Customer> and DbKey<Product> are distinct types. Currenty, this gives the desired type safety in every ADL target language except, unfortunately, typescript as you point out.

Are you aware of any approaches to emulating newtypes in typescript that would address this?

timbod7 avatar Jan 02 '21 04:01 timbod7

Here is the approach I sometimes use. It's ugly but gets the job done. Benefits are that it is very lightweight and standalone, and also has zero runtime cost.

export class DbKey<T> {
    private constructor() {}

    public static wrap<T>(val: string): DbKey<T> {
        return val as any;
    }

    public static unwrap<T>(val: DbKey<T>): string {
        return val as any;
    }

    protected dummy: [DbKey<T>, T] = null as any;
}


export interface Customer {
    name: string;
    address: string;
};

export interface Product {
    id: number;
}

export function test(x: DbKey<Customer>): DbKey<Product> {
    return x;    // error: Type 'DbKey<Customer>' is not assignable to type 'DbKey<Product>'.
}

bitc avatar Jan 06 '21 13:01 bitc