diff --git a/front_end/elements/ComputedStyleProperty_bridge.js b/front_end/elements/ComputedStyleProperty_bridge.js index 724068dd0e..704a8a9dbd 100644 --- a/front_end/elements/ComputedStyleProperty_bridge.js +++ b/front_end/elements/ComputedStyleProperty_bridge.js @@ -17,7 +17,7 @@ import './ComputedStyleProperty.js'; * inherited:boolean, * traceable:boolean, * expanded:boolean, -* onNavigateToSource:function(Event):void, +* onNavigateToSource:function(!Event=):void, * }} */ // @ts-ignore we export this for Closure not TS diff --git a/front_end/elements/ComputedStyleTrace_bridge.js b/front_end/elements/ComputedStyleTrace_bridge.js index a6ee0ea1db..cd9758d92e 100644 --- a/front_end/elements/ComputedStyleTrace_bridge.js +++ b/front_end/elements/ComputedStyleTrace_bridge.js @@ -14,7 +14,7 @@ import './ComputedStyleTrace.js'; * @typedef {{ * selector:string, * active:boolean, -* onNavigateToSource:function(Event):void, +* onNavigateToSource:function(!Event=):void, * }} */ // @ts-ignore we export this for Closure not TS diff --git a/front_end/elements/ComputedStyleWidget.js b/front_end/elements/ComputedStyleWidget.js index 5345c5cc3d..d83358c802 100644 --- a/front_end/elements/ComputedStyleWidget.js +++ b/front_end/elements/ComputedStyleWidget.js @@ -92,7 +92,7 @@ const createTraceElement = (node, property, isPropertyOverloaded, matchedStyles, trace.data = { selector: rule ? rule.selectorText() : 'element.style', active: !isPropertyOverloaded, - onNavigateToSource: /** @type {function(?Event):void} */ (navigateToSource.bind(null, property)), + onNavigateToSource: /** @type {function(!Event=):void} */ (navigateToSource.bind(null, property)), }; return trace; @@ -376,7 +376,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget { const propertyElement = createPropertyElement(node, propertyName, propertyValue); const trace = propertyTraces.get(propertyName); - /** @type {function(?Event):void} */ + /** @type {function(!Event=):void} */ let navigate = () => {}; if (trace) { const traceContainer = document.createElement('div'); @@ -390,7 +390,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget { 'contextmenu', this._handleContextMenuEvent.bind( this, /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), activeProperty)); - navigate = /** @type {function(?Event):void} */ (navigateToSource.bind(this, activeProperty)); + navigate = /** @type {function(!Event=):void} */ (navigateToSource.bind(this, activeProperty)); propertyElement.appendChild(traceContainer); propertyElement.addEventListener('traces-toggled', this._onTracesToggled.bind(this)); } @@ -467,7 +467,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget { const propertyElement = createPropertyElement(node, propertyName, propertyValue); const trace = propertyTraces.get(propertyName); - /** @type {function(?Event):void} */ + /** @type {function(!Event=):void} */ let navigate = () => {}; if (trace) { const traceContainer = document.createElement('div'); @@ -478,7 +478,7 @@ export class ComputedStyleWidget extends UI.ThrottledWidget.ThrottledWidget { 'contextmenu', this._handleContextMenuEvent.bind( this, /** @type {!SDK.CSSMatchedStyles.CSSMatchedStyles} */ (matchedStyles), activeProperty)); - navigate = /** @type {function(?Event):void} */ (navigateToSource.bind(this, activeProperty)); + navigate = /** @type {function(!Event=):void} */ (navigateToSource.bind(this, activeProperty)); propertyElement.appendChild(traceContainer); propertyElement.addEventListener('traces-toggled', this._onTracesToggled.bind(this)); } diff --git a/scripts/component_bridges/value_for_type_node.ts b/scripts/component_bridges/value_for_type_node.ts index 0241a79edd..d358523071 100644 --- a/scripts/component_bridges/value_for_type_node.ts +++ b/scripts/component_bridges/value_for_type_node.ts @@ -128,7 +128,22 @@ export const valueForTypeNode = (node: ts.TypeNode, isFunctionParam: boolean = f if (!param.type) { return ''; } - return valueForTypeNode(param.type); + + const valueForParam = valueForTypeNode(param.type, true); + + if (nodeIsPrimitive(param.type)) { + // A primitive never has a ! at the start, but does have a = at the end if it's optional. + return param.questionToken ? `${valueForParam}=` : valueForParam; + } + + // If it's not a primitive, it's a type ref and needs a + // non-nullable ! at the start and a = at the end if + // it's optional. + return [ + '!', + valueForTypeNode(param.type, true), + param.questionToken ? '=' : '', + ].join(''); }) .join(', '); diff --git a/test/unittests/scripts/component_bridges/value_for_type_node_test.ts b/test/unittests/scripts/component_bridges/value_for_type_node_test.ts index b7a37c0a83..72c029e3db 100644 --- a/test/unittests/scripts/component_bridges/value_for_type_node_test.ts +++ b/test/unittests/scripts/component_bridges/value_for_type_node_test.ts @@ -237,5 +237,39 @@ describe('valueForTypeNode', () => { const node = ts.createFunctionTypeNode([], [stringParam], returnUnionNode); assert.strictEqual(valueForTypeNode(node), 'function(string):(string|undefined)'); }); + + it('correctly deals with optional type reference parameters', () => { + const stringNode = createNode(ts.SyntaxKind.StringKeyword); + const typeReferenceNode = ts.createTypeReferenceNode(ts.createIdentifier('ExampleInterface'), []); + const functionParam = ts.createParameter( + [], [], undefined, ts.createIdentifier('foo'), ts.createToken(ts.SyntaxKind.QuestionToken), + typeReferenceNode); + + // function(foo?: ExampleInterface):string + const node = ts.createFunctionTypeNode([], [functionParam], stringNode); + assert.strictEqual(valueForTypeNode(node), 'function(!ExampleInterface=):string'); + }); + + it('correctly deals with required type reference parameters', () => { + const stringNode = createNode(ts.SyntaxKind.StringKeyword); + const typeReferenceNode = ts.createTypeReferenceNode(ts.createIdentifier('ExampleInterface'), []); + const functionParam = + ts.createParameter([], [], undefined, ts.createIdentifier('foo'), undefined, typeReferenceNode); + + // function(foo: ExampleInterface):string + const node = ts.createFunctionTypeNode([], [functionParam], stringNode); + assert.strictEqual(valueForTypeNode(node), 'function(!ExampleInterface):string'); + }); + + it('correctly deals with optional primitive parameters', () => { + const returnTypeNode = createNode(ts.SyntaxKind.StringKeyword); + const stringParam = ts.createParameter( + [], [], undefined, ts.createIdentifier('foo'), ts.createToken(ts.SyntaxKind.QuestionToken), + createNode(ts.SyntaxKind.StringKeyword)); + const node = ts.createFunctionTypeNode([], [stringParam], returnTypeNode); + + // function(foo?: string):string + assert.strictEqual(valueForTypeNode(node), 'function(string=):string'); + }); }); });