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

Excess property checking only applies to half of an intersection #30715

Closed
brunostuani opened this issue Apr 2, 2019 · 5 comments · Fixed by #32582
Closed

Excess property checking only applies to half of an intersection #30715

brunostuani opened this issue Apr 2, 2019 · 5 comments · Fixed by #32582
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@brunostuani
Copy link

TypeScript Version: 3.3.333

Search Terms:
Type infer array nested interface structure

Code

interface ValueOnly {
  value: number | null;
}

interface ValueAndKey {
  key: string | null;
  value: number | null;
}

interface ValueOnlyFields {
  fields: Array<ValueOnly>;
}

interface ValueAndKeyFields {
  fields: Array<ValueAndKey>;
}

interface BugRepro {
  dataType: ValueAndKeyFields & ValueOnlyFields;
}

interface BugReproWithoutArray {
  dataType: ValueAndKey & ValueOnly;
}

// This. Having the "key" errors out because of extra "key" field,
// while not having the "key" makes it complain that "key" is missing.
const repro: BugRepro = {
  dataType: {
    fields: [{
      key: 'bla',
      value: null,
    }],
  }
}

// Without nesting the type inside of an array, it can infer the type nicely.
const reproWithoutArray: BugReproWithoutArray = {
  dataType: {
    key: 'bla',
    value: null,
  },
}

Expected behavior:
Compiler should not complain that "key" is defined.

Actual behavior:
Compiler cannot identify that the array is neither Array, and Array without me casting it.

Playground Link:
https://www.typescriptlang.org/play/#src=interface%20ValueOnly%20%7B%0D%0A%20%20value%3A%20number%20%7C%20null%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20ValueAndKey%20%7B%0D%0A%20%20key%3A%20string%20%7C%20null%3B%0D%0A%20%20value%3A%20number%20%7C%20null%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20ValueOnlyFields%20%7B%0D%0A%20%20fields%3A%20Array%3CValueOnly%3E%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20ValueAndKeyFields%20%7B%0D%0A%20%20fields%3A%20Array%3CValueAndKey%3E%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20BugRepro%20%7B%0D%0A%20%20dataType%3A%20ValueAndKeyFields%20%26%20ValueOnlyFields%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20BugReproWithoutArray%20%7B%0D%0A%20%20dataType%3A%20ValueAndKey%20%26%20ValueOnly%3B%0D%0A%7D%0D%0A%0D%0A%2F%2F%20This.%20Having%20the%20%22key%22%20errors%20out%20because%20of%20extra%20%22key%22%20field%2C%0D%0A%2F%2F%20while%20not%20having%20the%20%22key%22%20makes%20it%20complain%20that%20%22key%22%20is%20missing.%0D%0Aconst%20repro%3A%20BugRepro%20%3D%20%7B%0D%0A%20%20dataType%3A%20%7B%0D%0A%20%20%20%20fields%3A%20%5B%7B%0D%0A%20%20%20%20%20%20key%3A%20'bla'%2C%0D%0A%20%20%20%20%20%20value%3A%20null%2C%0D%0A%20%20%20%20%7D%5D%2C%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aconst%20reproWithoutArray%3A%20BugReproWithoutArray%20%3D%20%7B%0D%0A%20%20dataType%3A%20%7B%0D%0A%20%20%20%20key%3A%20'bla'%2C%0D%0A%20%20%20%20value%3A%20null%2C%0D%0A%20%20%7D%2C%0D%0A%7D%0D%0A%0D%0A

Related Issues:
Couldn't find.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Apr 2, 2019
@RyanCavanaugh
Copy link
Member

Either an EPC bug or "Not all intersection types are necessarily constructable"

@ExE-Boss
Copy link
Contributor

ExE-Boss commented Apr 6, 2019

It works if you do:

interface ValueOnly {
	value: number | null;
}

interface ValueAndKey {
	key: string | null;
	value: number | null;
}

interface ValueOnlyFields {
	fields: Array<ValueOnly>;
}

interface ValueAndKeyFields {
	fields: Array<ValueAndKey>;
}

interface BugRepro {
	// Note the union (`|`) instead of intersection (`&`)
	dataType: ValueAndKeyFields & ValueOnlyFields;
}

interface BugReproWithoutArray {
	dataType: ValueAndKey & ValueOnly;
}

// This. Having the "key" errors out because of extra "key" field,
// while not having the "key" makes it complain that "key" is missing.
const repro: BugRepro = {
	dataType: {
		fields: [
			// Note the explicit type cast / declaration:
			<ValueAndKey>{
				key: 'bla',
				value: null,
			},
		],
	},
};

const reproWithoutArray: BugReproWithoutArray = {
	dataType: {
		key: 'bla',
		value: null,
	},
};

Playground link: https://www.typescriptlang.org/play/#src=🔗

@brunostuani
Copy link
Author

I understand. As I said I could just typecast and it will work, but it should without typecasting.

@sandersn
Copy link
Member

@weswigham or @andrewbranch I thought I heard something recently from one of you about better handling of intersections wrt excess property checks. Does that sound familiar? I haven't touched this code in a while and I thought that it used to have intersection-specific code. (Maybe I'm thinking of weak type checking.)

@sandersn
Copy link
Member

Probably thinking of this: #30853

@sandersn sandersn changed the title Cannot infer type of structure inside an array Excess property checking only applies to half of an intersection Jul 26, 2019
@sandersn sandersn added the Fix Available A PR has been opened for this issue label Jul 26, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants