marvinav
marvinav

Reputation: 717

Return generic type of type alias

I Have A Type with two generic parameters

type FirstLevelType<A, Z> = {
  _: "typeCheck";
};

But I Need Wrap this type with another

type TestWrapperType<T, U> = FirstLevelType<T, U>;

After I have create variable with TestWrapperType, I need to get generic parameters.

const a: TestWrapperType<{ cat: string }, { dog: number }> = {
  _: "typeCheck",
};

But I can use only FirstLevelType to prevent growing code length, because wrapper types can be created many times.

type ExtendFirst = typeof a extends FirstLevelType<infer T, infer U>
  ? T
  : "not extended";

Resulted type = unknown

Excepted type = {cat: string}

type ExtendWrapper = typeof a extends TestWrapperType<infer T, infer U>
  ? T
  : "not extended";

Resulted type = {cat: string}

Excepted type = {cat: string}

Why ExtendFirst type is unknown? And how can I solve this issue.

[Update 1]

If FirstLevelType declared as interface, when Resulted Type will be correct. However, when my wrapper has other properties, resulted type unknow again.

type TestWrapperType<T, U> = FirstLevelType<T, U> & {
  seal?: boolean;
};

Upvotes: 2

Views: 462

Answers (1)

If you want to make it work, just use interface for FirstLevelType instead of type.

// used interface instead of type
interface FirstLevelType<A, Z> {
    _: "typeCheck";
};

type TestWrapperType<T, U> = FirstLevelType<T, U>;


const a: TestWrapperType<{ cat: string }, { dog: number }> = {
  _: "typeCheck",
};

type ExtendFirst = typeof a extends FirstLevelType<infer T, infer _>
    ? T
    : "not extended";


type ExtendWrapper = typeof a extends TestWrapperType<infer T, infer _>
    ? T
    : "not extended";

Playground

I believe this is because interfaces are lazy evaluated when types - eagerly.

If FirstLevelType declared as interface, when Resulted Type will be correct. However, when my wrapper has other properties, resulted type unknow again.

Since your TestWrapperType might be extended, you should infer these rest props:

type FirstLevelType<A, Z> = {
    _: "typeCheck";
};


type TestWrapperType<T, U> = FirstLevelType<T, U> & {
    seal?: boolean;
}

const a: TestWrapperType<{ cat: string }, { dog: number }> = {
    _: "typeCheck",
};

// { cat: string; }
type ExtendFirst = typeof a extends FirstLevelType<infer T, infer _> & infer RestProps
    ? T
    : "not extended";

Now you can use type for FirstLevelType

Upvotes: 2

Related Questions