Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/transform-inline/visitor-context.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface VisitorContext extends PartialVisitorContext {
functionNames: Set<string>;
functionMap: Map<string, ts.FunctionDeclaration>;
typeIdMap: Map<string, string>;
overrideDisallowSuperfluousObjectProperies?: boolean;
}

export interface PartialVisitorContext {
Expand Down
9 changes: 7 additions & 2 deletions src/transform-inline/visitor-type-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,11 @@ function visitLiteralType(type: ts.LiteralType, visitorContext: VisitorContext)
}

function visitUnionOrIntersectionType(type: ts.UnionOrIntersectionType, visitorContext: VisitorContext) {
let disallowSuperfluousPropertyCheck = visitorContext.options.disallowSuperfluousObjectProperties;
if (visitorContext.overrideDisallowSuperfluousObjectProperies) {
visitorContext.overrideDisallowSuperfluousObjectProperies = false;
disallowSuperfluousPropertyCheck = false;
}
const typeUnion = type;
if (tsutils.isUnionType(typeUnion)) {
const name = VisitorTypeName.visitType(type, visitorContext, { type: 'type-check' });
Expand All @@ -496,8 +501,8 @@ function visitUnionOrIntersectionType(type: ts.UnionOrIntersectionType, visitorC
if (tsutils.isIntersectionType(intersectionType)) {
const name = VisitorTypeName.visitType(type, visitorContext, { type: 'type-check', superfluousPropertyCheck: visitorContext.options.disallowSuperfluousObjectProperties });
return VisitorUtils.setFunctionIfNotExists(name, visitorContext, () => {
const functionNames = intersectionType.types.map((type) => visitType(type, { ...visitorContext, options: { ...visitorContext.options, disallowSuperfluousObjectProperties: false } }));
if (visitorContext.options.disallowSuperfluousObjectProperties) {
const functionNames = intersectionType.types.map((type) => visitType(type, { ...visitorContext, overrideDisallowSuperfluousObjectProperies: true }));
if (disallowSuperfluousPropertyCheck) {
// Check object keys at intersection type level. https://github.com/woutervh-/typescript-is/issues/21
const keys = VisitorIsStringKeyof.visitType(type, visitorContext);
if (keys instanceof Set) {
Expand Down
40 changes: 40 additions & 0 deletions test/issue-111.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as assert from 'assert';
import { assertEquals } from '../index';

/* https://github.com/woutervh-/typescript-is/issues/111 */

// To properly test this issue, set disallowSuperfluousObjectProperties to `true` in the configuration.
// Then inspect the generated code to see if the keys of the object are checked properly.

describe('assertEquals', () => {
describe('assertEquals<BarIntersection>', () => {
type Foo = {
quux: string;
};

type BarIntersection = {
foo: Foo;
} & {
bar: string;
};

type BarNotIntersection = {
foo: Foo;
bar: string;
};

const document = {
bar: 'bar',
foo: {
quux: 'quux',
super: 'fluous'
}
};

it('should throw with invalid objects', () => {
assert.throws(() => assertEquals<Foo>(document.foo));
assert.throws(() => assertEquals<BarNotIntersection>(document));
assert.throws(() => assertEquals<BarIntersection>(document));
});
});
});