Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce common type traits #20780

Closed
Viatorus opened this issue Dec 19, 2017 · 3 comments
Closed

Introduce common type traits #20780

Viatorus opened this issue Dec 19, 2017 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@Viatorus
Copy link

Viatorus commented Dec 19, 2017

In accordance with getting the type of any typeof expression I suggest to add common type traits to TypeScript.

I come from a C++ background where template programming / meta-programming is heavily used. The ISO C++ Standard defines type traits, which can be very useful in detection and modifying types in TypeScript.

Defining type traits in the TypeScript core language has a huge benefits in publicity and universal applicability instead of moving such a feature to an external extension. Type traits should extent the already known one: Partial, Readonly, Record and Pick.

Here are some type trait example, which can be usefull in TypeScript. Syntax, naming and wording is not fixed. Please have also a look at the standardized type traits in C++.

Please excuse my bad English. ;)

Structure

  • The type true represent a successful evaluation of a type trait.
  • The type false represents a unsuccessful evaluation of a type trait.

EnableIf

Enables a type T, if a is true. Otherwise the type is never.

Possible implementation

function EnableIf<T = void>(a: true, t?: T): T;
function EnableIf<T = void>(a: false, t?: T): never;
function EnableIf(a: any, t?: any): any {
    return null;
}

Example

let en_if1 = EnableIf<number>(true);
en_if1 = 1;
let en_if2 = EnableIf<number>(false);
en_if2 = 1; // Error

CompileIf

Compiles only if T is true. Otherwise a compile error will be raised.

Possible implementation

function CompileIf<T = void>(a: true, t?: T): T {
    return null as any as T;
}

Example

CompileIf(true);
CompileIf(false); // Error

IsBoolean

The result is true, if the type is boolean. Otherwise false.

function IsBoolean(a: boolean): true;
function IsBoolean(a: any): false;
function IsBoolean(a: any): any {
    return null;  
}

Example

CompileIf(IsBoolean(true));
CompileIf(IsBoolean(1)); // Error

IsNumber

The result is true, if the type is number. Otherwise false.

function IsNumber(a: number): true;
function IsNumber(a: any): false;
function IsNumber(a: any): any {
    return null;  
}

Example

CompileIf(IsNumber(1));
CompileIf(IsNumber("12")); // Error

IsString

The result is true, if the type is string. Otherwise false.

function IsString(a: string): true;
function IsString(a: any): false;
function IsString(a: any): any {
    return null;  
}

Example

CompileIf(IsString("123");
CompileIf(IsString(1)); // Error

IsArray

The result is true, if the type is array. Otherwise false.

function IsArray<T>(a: T[]): true;
function IsArray(a: any): false;
function IsArray(a: any): any {
    return null;
}

Example

CompileIf(IsArray([1, 2]));
CompileIf(IsArray(1)); // Error

IsObject

The result is true, if the type is object. Otherwise false.

function IsObject<T extends object>(a: T): true;
function IsObject(a: any): false;
function IsObject(a: any): any {
    return null;
}

Example

CompileIf(IsObject({}));
CompileIf(IsObject(1)); // Error

IsNull

The result is true, if the type is null. Otherwise false.

function IsNull(a: null): true;
function IsNull(a: any): false;
function IsNull(a: any): any {
    return null;
}

Example

CompileIf(IsNull(null));
CompileIf(IsNull(1)); // Error

IsClass

The result is true, if the type is a class type. Otherwise false.

function IsClass<T>(a: { new(...args: any[]): T }): true;
function IsClass(a: any): false;
function IsClass(a: any): any {
    return null;
}

Example

class A {}

CompileIf(IsClass(A));
CompileIf(IsClass({})); // Error

IsSame

The result is true, if two types are identical. Otherwise false.

Possible implementation

function IsSame<T>(a: T, b: T): true;
function IsSame(a: any, b: any): false;
function IsSame(a: any, b: any): any {
    return null;
}

Example

CompileIf(IsSame(1, 1));
CompileIf(IsSame(1, "12")); // Error

IsExtension

The result is true, if a type is an extension of another type. Otherwise false.

Possible implementation

function IsExtension<T, U extends T>(a: T, b: U): true;
function IsExtension<T, U>(a: T, b: U): false;
function IsExtension(a: any, b: any): any {
    return null;
}

Example

class A {}

class B extends A {
    private a: number;
}

class C {
    private c: number;
}

CompileIf(IsExtension(A, B));
CompileIf(IsExtension(B, A)); // Error
CompileIf(IsExtension(C, B)); // Error
CompileIf(IsExtension(B, C)); // Error

RemoveExtend

Removes one extent from the given array type.

Possible implementation

function RemoveExtend<T>(a: T[]): T;
function RemoveExtend<T>(a: T): T;
function RemoveExtend(a: any): any {
    return null as any;
}

Example

let re_ext1 = RemoveExtend([1, 2]);
re_ext1 = 2;
let re_ext2 = RemoveExtend(1);
re_ext2 = 2;
let re_ext3 = RemoveExtend([[1, 2]]);
re_ext3 = [3, 4];

Real world example:

Here is on real world example, where I (for LokiJS2, an in-memory database) would use it. The available filter operations depends on the type of the property:

 export type LokiOps<R> = {
    $eq?: R;
    $aeq?: R;
    $ne?: R;
    // ...
    $lte?: R;
    $between?: [R, R];
    // ..
    $contains?: EnableIf(IsArray(R), RemoveExtend(R));
    // ...
  };

Final note

All examples above do already compile (except the real world example).

  • What do you think about type traits?
  • Which type traits do you miss?
  • What syntax/naming would you like?
@ghost
Copy link

ghost commented Dec 19, 2017

Possibly related to #12424

@DanielRosenwasser
Copy link
Member

Thanks for the write-up! However, given our current direction (notes at #20724), I think I'm going to mark this as a duplicate of #12424.

@DanielRosenwasser DanielRosenwasser added the Duplicate An existing issue was already created label Dec 19, 2017
@Viatorus
Copy link
Author

I am glad that a similar feature target this.

Thank you.

@microsoft microsoft locked and limited conversation to collaborators Jun 21, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

2 participants