Skip to content

Commit

Permalink
Class: Fix type inference (#701)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajvincent authored Nov 13, 2023
1 parent 59411c8 commit 7294cf0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
4 changes: 2 additions & 2 deletions source/basic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Matches a [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
@category Class
*/
export type Class<T, Arguments extends unknown[] = any[]> = {
prototype: T;
prototype: Pick<T, keyof T>;
new(...arguments_: Arguments): T;
};

Expand All @@ -25,7 +25,7 @@ We cannot use a `type` here because TypeScript throws: 'abstract' modifier canno
*/
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export interface AbstractClass<T, Arguments extends unknown[] = any[]> extends AbstractConstructor<T, Arguments> {
prototype: T;
prototype: Pick<T, keyof T>;
}

/**
Expand Down
32 changes: 30 additions & 2 deletions test-d/abstract-class.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectError, expectAssignable, expectNotAssignable} from 'tsd';
import type {AbstractConstructor, AbstractClass} from '../index';
import {expectError, expectAssignable, expectNotAssignable, expectType} from 'tsd';
import type {AbstractConstructor, AbstractClass, IsAny} from '../index';

abstract class Foo {
constructor(x: number) {
Expand Down Expand Up @@ -59,3 +59,31 @@ expectNotAssignable<{fooMethod(): void}>(Bar.prototype);
expectError(new CorrectConcreteExtendedBar(12));
expectAssignable<{barMethod(): void}>(new CorrectConcreteExtendedBar(12, 15));
// /Prototype test

// Prototype test with type parameter
abstract class AbstractBuilding<T = unknown> {
owners: T;
constructor(buildingOwners: T) {
this.owners = buildingOwners;
}
}

type Census = {
count: number;
};

abstract class House<OwnerCount extends Census = Census> extends AbstractBuilding<OwnerCount> {}

class CityBlock<BuildingType extends AbstractBuilding<Census>> {
residence: BuildingType;

constructor(HousingType: AbstractClass<BuildingType, [Census]>) {
class Building extends HousingType {}
this.residence = new Building({count: 2});
}
}

const Family = (new CityBlock(House)).residence.owners;
expectType<IsAny<typeof Family>>(false);
expectAssignable<number>(Family.count);
// /Prototype test with type parameter
27 changes: 27 additions & 0 deletions test-d/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,30 @@ expectType<PositionProps>(Position.prototype);

expectError(new Position(17));
expectAssignable<PositionProps>(new Position(17, 34));

// Prototype test with type parameter
class Building<T = unknown> {
owners: T;
constructor(buildingOwners: T) {
this.owners = buildingOwners;
}
}

type Census = {
count: number;
};

class House<OwnerCount extends Census = Census> extends Building<OwnerCount> {}

class CityBlock<BuildingType extends Building> {
residence: BuildingType;

constructor(HousingType: Class<BuildingType, [Census]>) {
this.residence = new HousingType({count: 2});
}
}

const Family = (new CityBlock(House)).residence.owners;
expectType<IsAny<typeof Family>>(false);
expectAssignable<number>(Family.count);
// /Prototype test with type parameter

0 comments on commit 7294cf0

Please sign in to comment.