dsherret / conditional-type-checks

Types for testing TypeScript types.
MIT License
449 stars 19 forks source link

Add IsAssignable #9

Open dsherret opened 5 years ago

dsherret commented 5 years ago

Similar to IsExact, but less strict.

lazarljubenovic commented 5 years ago

For a moment I thought this could be a solution for https://github.com/dsherret/ts-morph/issues/357, and I got so excited :smile: But just to be sure: although all of assertions in this repo are kinda meta-ish, none would be of any help when analyzing code statically, right? You'd still need to actually run the full TypeScript compiler and enable type checking in order to statically determine if two types are assignable to one other, by only looking at source code?

dsherret commented 5 years ago

@lazarljubenovic hah, I wish! Yeah, that's still not exposed in the compiler api 😢

smmoosavi commented 4 years ago

and IsNotAssignable type

dsherret commented 4 years ago

@smmoosavi wouldn't need that as the API currently supports checking that one of these types resolves to false. For example:

assert<IsNullable<string>>(false);
// or
type doTest = AssertFalse<IsNever<typeof result>>;
// or
type doTest2 = Assert<Has<typeof result, number>, false>;
smmoosavi commented 4 years ago

It is about readability.

type doTest = AssertTrue<
  IsNotAssignable<
    ActionListener<Animal>,
    ActionListener<Dog>
    >,
  >

or

type doTest = AssertTrue<
  IsAssignable<
    ActionListener<Dog>,
    ActionListener<Animal>
    >,
  >
dsherret commented 4 years ago

@smmoosavi seems just as readable?

type doTest = AssertFalse<
  IsAssignable<
    ActionListener<Animal>,
    ActionListener<Dog>
  >
>

Should there be IsNotX types for everything to be consistent? Why not just?

type doTest = AssertTrue<
  Not<IsAssignable<
    ActionListener<Animal>,
    ActionListener<Dog>
  >>
>

...though, I don't think that is worth adding.

smmoosavi commented 4 years ago

potential implementation

true if T is assignable to U

type IsAssignable<T, U> = T extends U ? true : false

example:

type IsAssignable<T, U> = T extends U ? true : false

type C<T> = (c: T) => void 

interface A{ a: string }
interface B{ b: number }
interface AB{a:string,b:number}

type CA = C<A>
type CB = C<B>
type CAB = C<AB>

type x1 = IsAssignable<AB, A> // true 
type x2 = IsAssignable<B, A> // false
type x3 = IsAssignable<A, AB> // false
type x4 = IsAssignable<CA, CAB> // true
type x5 = IsAssignable<CAB, CA> // false

T extends U ? X : Y

The type above means when T is assignable to U the type is X, otherwise the type is Y.

source: https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types

Gerrit0 commented 4 years ago

type IsAssignable<T, U> = T extends U ? true : false

This isn't a good implementation. With IsAssignable<A | B, B> it gives boolean because T is a bare type parameter and we distribute. A better implementation would be:

type IsAssignable<T, U> = [T] extends [U] ? true : false
unional commented 2 years ago

https://github.com/unional/type-plus/blob/main/ts/predicates/CanAssign.ts

🌷