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

Proposal: Add IsAssignable Utility Type #3

Open
Snowflyt opened this issue Dec 26, 2023 · 4 comments
Open

Proposal: Add IsAssignable Utility Type #3

Snowflyt opened this issue Dec 26, 2023 · 4 comments

Comments

@Snowflyt
Copy link

I've noticed the library currently lacks a IsAssignable<T, U> utility type for checking assignment compatibility between types, which is a common task in TypeScript.

type IsAssignable<A, B> = [A] extends [B] ? true : false;

This utility works similar to type Extends<A, B> = A extends B ? true : false, but it never evaluates to never or boolean and works better with unions and intersections.

type A = IsAssignable<string, string>;
//   ^? true
type B = IsAssignable<'foo', string>;
//   ^? true
type C = IsAssignable<never, never>; // Only `never` is assignable to `never`
//   ^? true
type D = IsAssignable<1 | 2, 1>; // Union type is correctly handled
//   ^? false
type E = IsAssignable<1 & 2, never>; // Only `never` is assignable to `never`
//   ^? true
type F = IsAssignable<string & number, never>; // Only `never` is assignable to `never`
//   ^? true
type G = IsAssignable<any, {}>; // `any` is assignable to all types
//   ^? true
type H = IsAssignable<{}, any>; // `any` is assignable to all types
//   ^? true
type I = IsAssignable<any, 1>; // `any` is assignable to all types
//   ^? true
type J = IsAssignable<never, 1>; // `never` is assignable to all types
//   ^? true
type K = IsAssignable<any, never>; // Only `never` is assignable to `never`
//   ^? false
type L = IsAssignable<never, any>; // `never` is assignable to all types
//   ^? true
type M = IsAssignable<never, {}>; // `never` is assignable to all types
//   ^? true
type N = IsAssignable<boolean, true>; // Union type is correctly handled
//   ^? false

I'm not entirely certain if this type will work in more complex edge cases, but the scenarios listed here should cover a wide range of common cases.

@dimitropoulos
Copy link
Collaborator

I'd welcome a PR on this, but would you mind sharing a real-world use-case?

@jasikpark
Copy link

🤷 microsoft/TypeScript#56448

@jasikpark
Copy link

oh wait, that's not a type...

@Snowflyt
Copy link
Author

Snowflyt commented Jan 5, 2024

I'd welcome a PR on this, but would you mind sharing a real-world use-case?

It is more reliable than Extends when dealing with unions. I think.

import type { ArrayIndices, IntRange } from "type-fest";
import type { Expect, ExpectFalse, Extends } from "type-testing";

type IsAssignable<A, B> = [A] extends [B] ? true : false;

const values = ['a', 'b', 'c'] as const;
type ValueIndices = ArrayIndices<typeof values>;

type Cases_using_Extends = [
  Expect<Extends<IntRange<0, 2>, ValueIndices>>,
  Expect<Extends<IntRange<0, 3>, ValueIndices>>,
  ExpectFalse<Extends<IntRange<0, 4>, ValueIndices>>, // Error: `boolean` is not assignable to `false`
];

type Cases_using_IsAssignable = [
  Expect<IsAssignable<IntRange<0, 2>, ValueIndices>>,
  Expect<IsAssignable<IntRange<0, 3>, ValueIndices>>,
  ExpectFalse<IsAssignable<IntRange<0, 4>, ValueIndices>>, // OK
]

Try it on TS Playground.

It also avoids some of the strange behavior of Extends on never, making it a more intuitive and safer utility than Extends in most cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants