Skip to content

Generic interface should not be invariant when type arg only used in parameter list of function property  #32674

Closed
@AnyhowStep

Description

@AnyhowStep

TypeScript Version: 3.5.1

Search Terms:

generic interface, invariant, contravariant, type arg, parameter list, function property

Code

//strictFunctionTypes enabled
declare let _a : {
    //This is a function property, not a method
    _ : (arg : ["a", "b", bigint]) => void
};
declare let _b : {
    //This is a function property, not a method
    _ : (arg : ["a", "b", bigint|null]) => void
};
/**
 * Assignment OK!
 */
_a = _b;

/**
 * Assignment not allowed, as expected
 * 
 * Type '["a", "b", bigint | null]' is not assignable to type '["a", "b", bigint]'
 */
_b = _a;

////////////////////////////////////

type Transform<T extends { [tableAlias:string] : { [columnAlias:string] : any } }> = (
    {
        [tableAlias in keyof T] : (
            {
                [columnAlias in keyof T[tableAlias]] : (
                    [tableAlias, columnAlias, T[tableAlias][columnAlias]]
                )
            }[keyof T[tableAlias]]
        )
    }[keyof T]
);

interface X<T extends { [tableAlias:string] : { [columnAlias:string] : any } }> {
    //This is a function property, not a method
    _ : (arg : Transform<T>) => void
}

declare let ax : X<{
    a : {
        b : bigint,
    }
}>;
/**
 * ax._ : (arg: ["a", "b", bigint]) => void
 * _a._ : (arg: ["a", "b", bigint]) => void
 */
ax._

declare let bx : X<{
    a : {
        b : bigint|null,
    }
}>;
/**
 * bx._ : (arg: ["a", "b", bigint | null]) => void
 * _b._ : (arg: ["a", "b", bigint | null]) => void
 */
bx._

/**
 * Expected : Assignment OK!
 * Actual   : Assignment not allowed
 * 
 * Type '{ b: bigint | null; }' is not assignable to type '{ b: bigint; }'
 */
ax = bx;

/**
 * Assignment not allowed, as expected
 * 
 * Type '["a", "b", bigint | null]' is not assignable to type '["a", "b", bigint]'
 */
bx = ax;

//Assignment OK!
_a = ax;
//Assignment OK!
_a = bx;

/**
 * Assignment not allowed, as expected
 * 
 * Type '["a", "b", bigint | null]' is not assignable to type '["a", "b", bigint]'
 */
_b = ax;
//Assignment OK!
_b = bx;

//Assignment OK!
ax = _a;
//Assignment OK!
ax = _b;

/**
 * Assignment not allowed, as expected
 * 
 * Type '["a", "b", bigint | null]' is not assignable to type '["a", "b", bigint]'
 */
bx = _a;
//Assignment OK!
bx = _b;

Expected behavior:

This should be allowed,

ax = bx;

Actual behavior:

/**
 * Expected : Assignment OK!
 * Actual   : Assignment not allowed
 * 
 * Type '{ b: bigint | null; }' is not assignable to type '{ b: bigint; }'
 */
ax = bx;

Playground Link: Playground

Related Issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions