chore: upgrade to TypeScript 3.5 (#5556)

TS 3.5 got much stricter on writing changes to objects with varied types [1] so we have to do a bit of typecasting work to convince TS about the types of keys and values that we are setting.

Longer term we should think about a better data structure that avoids us having to jump through some hoops but for now I think this is a reasonable step to get us onto 3.5.

Same story regarding bindings on `window`: the easiest fix is to cast `window` to `any` for the code that adds to it. I'm sure we can come up with a more type-safe way of doing this in the future.

[1]: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#fixes-to-unsound-writes-to-indexed-access-types
This commit is contained in:
Jack Franklin 2020-03-31 09:48:09 +01:00 committed by GitHub
parent b9240b1664
commit 5e8d79bf98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 18 deletions

View File

@ -329,7 +329,9 @@ class AXNode {
role: this._role role: this._role
}; };
/** @type {!Array<keyof SerializedAXNode>} */ /** @enum {'name'|'value'|'description'|'keyshortcuts'|'roledescription'|'valuetext'} */
let UserStringProperties; // eslint-disable-line no-unused-vars
/** @type {!Array<UserStringProperties>} */
const userStringProperties = [ const userStringProperties = [
'name', 'name',
'value', 'value',
@ -338,13 +340,21 @@ class AXNode {
'roledescription', 'roledescription',
'valuetext', 'valuetext',
]; ];
/**
* @param {UserStringProperties} key
*/
const getUserStringPropertyValue = key => /** @type string */(properties.get(key));
for (const userStringProperty of userStringProperties) { for (const userStringProperty of userStringProperties) {
if (!properties.has(userStringProperty)) if (!properties.has(userStringProperty))
continue; continue;
node[userStringProperty] = properties.get(userStringProperty);
node[userStringProperty] = getUserStringPropertyValue(userStringProperty);
} }
/** @type {!Array<keyof SerializedAXNode>} */ /** @enum {'disabled'|'expanded'|'focused'|'modal'|'multiline'|'multiselectable'|'readonly'|'required'|'selected'} */
let BooleanProperties; // eslint-disable-line no-unused-vars
/** @type {!Array<BooleanProperties>} */
const booleanProperties = [ const booleanProperties = [
'disabled', 'disabled',
'expanded', 'expanded',
@ -356,18 +366,25 @@ class AXNode {
'required', 'required',
'selected', 'selected',
]; ];
/**
* @param {BooleanProperties} key
*/
const getBooleanPropertyValue = key => /** @type boolean */(properties.get(key));
for (const booleanProperty of booleanProperties) { for (const booleanProperty of booleanProperties) {
// WebArea's treat focus differently than other nodes. They report whether their frame has focus, // WebArea's treat focus differently than other nodes. They report whether their frame has focus,
// not whether focus is specifically on the root node. // not whether focus is specifically on the root node.
if (booleanProperty === 'focused' && this._role === 'WebArea') if (booleanProperty === 'focused' && this._role === 'WebArea')
continue; continue;
const value = properties.get(booleanProperty); const value = getBooleanPropertyValue(booleanProperty);
if (!value) if (!value)
continue; continue;
node[booleanProperty] = value; node[booleanProperty] = getBooleanPropertyValue(booleanProperty);
} }
/** @type {!Array<keyof SerializedAXNode>} */ /** @enum {'checked'|'pressed'} */
let TristateProperties; // eslint-disable-line no-unused-vars
/** @type {!Array<TristateProperties>} */
const tristateProperties = [ const tristateProperties = [
'checked', 'checked',
'pressed', 'pressed',
@ -378,29 +395,45 @@ class AXNode {
const value = properties.get(tristateProperty); const value = properties.get(tristateProperty);
node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false; node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
} }
/** @type {!Array<keyof SerializedAXNode>} */
/** @enum {'level'|'valuemax'|'valuemin'} */
let NumericalProperties; // eslint-disable-line no-unused-vars
/** @type {!Array<NumericalProperties>} */
const numericalProperties = [ const numericalProperties = [
'level', 'level',
'valuemax', 'valuemax',
'valuemin', 'valuemin',
]; ];
/**
* @param {NumericalProperties} key
*/
const getNumericalPropertyValue = key => /** @type number */(properties.get(key));
for (const numericalProperty of numericalProperties) { for (const numericalProperty of numericalProperties) {
if (!properties.has(numericalProperty)) if (!properties.has(numericalProperty))
continue; continue;
node[numericalProperty] = properties.get(numericalProperty); node[numericalProperty] = getNumericalPropertyValue(numericalProperty);
} }
/** @type {!Array<keyof SerializedAXNode>} */
/** @enum {'autocomplete'|'haspopup'|'invalid'|'orientation'} */
let TokenProperties; // eslint-disable-line no-unused-vars
/** @type {!Array<TokenProperties>} */
const tokenProperties = [ const tokenProperties = [
'autocomplete', 'autocomplete',
'haspopup', 'haspopup',
'invalid', 'invalid',
'orientation', 'orientation',
]; ];
/**
* @param {TokenProperties} key
*/
const getTokenPropertyValue = key => /** @type string */(properties.get(key));
for (const tokenProperty of tokenProperties) { for (const tokenProperty of tokenProperties) {
const value = properties.get(tokenProperty); const value = getTokenPropertyValue(tokenProperty);
if (!value || value === 'false') if (!value || value === 'false')
continue; continue;
node[tokenProperty] = value; node[tokenProperty] = getTokenPropertyValue(tokenProperty);
} }
return node; return node;
} }

View File

@ -444,8 +444,10 @@ class Page extends EventEmitter {
await Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(debugError))); await Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(debugError)));
function addPageBinding(bindingName) { function addPageBinding(bindingName) {
const binding = window[bindingName]; const win = /** @type * */ (window);
window[bindingName] = (...args) => { const binding = /** @type function(string):* */ (win[bindingName]);
win[bindingName] = (...args) => {
const me = window[bindingName]; const me = window[bindingName];
let callbacks = me['callbacks']; let callbacks = me['callbacks'];
if (!callbacks) { if (!callbacks) {
@ -677,10 +679,12 @@ class Page extends EventEmitter {
* @return {!Promise<?Puppeteer.Response>} * @return {!Promise<?Puppeteer.Response>}
*/ */
async reload(options) { async reload(options) {
const [response] = await Promise.all([ const result = await Promise.all([
this.waitForNavigation(options), this.waitForNavigation(options),
this._client.send('Page.reload') this._client.send('Page.reload')
]); ]);
const response = /** @type Puppeteer.Response */ (result[0]);
return response; return response;
} }
@ -759,10 +763,11 @@ class Page extends EventEmitter {
const entry = history.entries[history.currentIndex + delta]; const entry = history.entries[history.currentIndex + delta];
if (!entry) if (!entry)
return null; return null;
const [response] = await Promise.all([ const result = await Promise.all([
this.waitForNavigation(options), this.waitForNavigation(options),
this._client.send('Page.navigateToHistoryEntry', {entryId: entry.id}), this._client.send('Page.navigateToHistoryEntry', {entryId: entry.id}),
]); ]);
const response = /** @type Puppeteer.Response */ (result[0]);
return response; return response;
} }

View File

@ -21,7 +21,7 @@
"lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc", "lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc",
"doc": "node utils/doclint/cli.js", "doc": "node utils/doclint/cli.js",
"coverage": "cross-env COVERAGE=true npm run unit", "coverage": "cross-env COVERAGE=true npm run unit",
"tsc": "tsc -p .", "tsc": "tsc --version && tsc -p .",
"apply-next-version": "node utils/apply_next_version.js", "apply-next-version": "node utils/apply_next_version.js",
"bundle": "npx browserify -r ./index.js:puppeteer -o utils/browser/puppeteer-web.js", "bundle": "npx browserify -r ./index.js:puppeteer -o utils/browser/puppeteer-web.js",
"test-types": "node utils/doclint/generate_types && npx -p typescript@3.2 tsc -p utils/doclint/generate_types/test/", "test-types": "node utils/doclint/generate_types && npx -p typescript@3.2 tsc -p utils/doclint/generate_types/test/",
@ -61,7 +61,7 @@
"pixelmatch": "^4.0.2", "pixelmatch": "^4.0.2",
"pngjs": "^3.3.3", "pngjs": "^3.3.3",
"text-diff": "^1.0.1", "text-diff": "^1.0.1",
"typescript": "3.2.2" "typescript": "3.5.3"
}, },
"browser": { "browser": {
"./lib/BrowserFetcher.js": false, "./lib/BrowserFetcher.js": false,

View File

@ -98,7 +98,7 @@ function checkSources(sources) {
function serializeSymbol(symbol, circular = []) { function serializeSymbol(symbol, circular = []) {
const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration); const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
const name = symbol.getName(); const name = symbol.getName();
if (symbol.valueDeclaration.dotDotDotToken) { if (symbol.valueDeclaration && symbol.valueDeclaration.dotDotDotToken) {
const innerType = serializeType(type.typeArguments[0], circular); const innerType = serializeType(type.typeArguments[0], circular);
innerType.name = '...' + innerType.name; innerType.name = '...' + innerType.name;
return Documentation.Member.createProperty('...' + name, innerType); return Documentation.Member.createProperty('...' + name, innerType);
@ -120,6 +120,12 @@ function checkSources(sources) {
return false; return false;
if (type.getCallSignatures().length) if (type.getCallSignatures().length)
return false; return false;
if (type.isLiteral())
return false;
if (type.isUnion())
return false;
return true; return true;
} }