Skip to content

Generic type parameter not inferring properly #58651

Closed as not planned
Closed as not planned
@dpizzo-at-aops

Description

@dpizzo-at-aops

🔎 Search Terms

"object key order matters"
"infer first occurrence"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about generics
  • This changed (for the better) between versions 4.6.4 and 4.7.4 (more info below)

⏯ Playground Link

playground

💻 Code

export type Foo = {
	foo: string;
};

export type Constraint<F extends Foo> = {
	part1(): F;
	part2(p1: F): void;
};

export type Constraint2<F extends Foo> = {
	part1(): F;
	part2(p1: NoInfer<F>): void;
};

// Replacing `Constraint` with `Constraint2` has no difference
export const inferStuff = <F extends Foo>(thing: Constraint<F>) => {
	return thing;
};

// This correctly infers the type parameter to have both the `foo` and `bar` keys ...
const correct = inferStuff({
	part1() {
		return {
			foo: "bar",
			bar: "baz",
		};
	},
	part2(p1) {},
});

// ... while this does not ...
const incorrect = inferStuff({
	part2(p1) {},
	part1() {
		return {
			foo: "bar",
			bar: "baz",
		};
	},
})

// ... but this does again ?
const whatIsHappening = inferStuff({
	part2() {},
	part1() {
		return {
			foo: "bar",
			bar: "baz",
		};
	},
})

🙁 Actual behavior

When part1 appears before part2, or when the parameter to part2 is omitted, then the type parameter is properly inferred. When part2 appears before part1 with a parameter, then the type parameter is inferred incorrectly, even when using Constraint2 which has NoInfer on that parameter's type.

In 4.6.4 and below, correct has the same type as incorrect (the order of the keys in the object didn't matter, but inferred less specifically).

🙂 Expected behavior

All three usages should be equivalent to each other, and in particular, should infer as Constraint<{ foo: string; bar: string; }>.

Additional information about the issue

Here's another example, that shows relatedly incorrect behavior: playground

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions