diff --git a/src/angular-app/bellows/apps/activity/activity-container.component.ts b/src/angular-app/bellows/apps/activity/activity-container.component.ts index 0722873bbe..2987e621ee 100644 --- a/src/angular-app/bellows/apps/activity/activity-container.component.ts +++ b/src/angular-app/bellows/apps/activity/activity-container.component.ts @@ -42,10 +42,10 @@ class Activity { userHrefRelated: string; icon: string; - constructor(data: object = {}) { + constructor(data: Record = {}) { if (data != null) { for (const property of Object.keys(data)) { - this[property] = data[property]; + this[property as keyof Activity] = data[property]; } } } @@ -57,6 +57,7 @@ class Activity { for (const index in this.content) { if (this.content.hasOwnProperty(index)) { if (index.startsWith('oldValue')) { + // @ts-expect-error Typescript should understand .hasOwnProperty, but doesn't return Activity.parseValue(this.content[index]); } } @@ -72,6 +73,7 @@ class Activity { for (const index in this.content) { if (this.content.hasOwnProperty(index)) { if (index.startsWith('newValue')) { + // @ts-expect-error Typescript should understand .hasOwnProperty, but doesn't return Activity.parseValue(this.content[index]); } } @@ -89,6 +91,7 @@ class Activity { for (const index in this.content) { if (this.content.hasOwnProperty(index)) { if (index.startsWith('fieldLabel')) { + // @ts-expect-error Typescript should understand .hasOwnProperty, but doesn't let label = this.content[index]; if (index.includes('#examples')) { label = 'Example - ' + label; @@ -164,8 +167,8 @@ class ActivityUserGroup { getSummaryDescription(entryId: string) { let summary = ''; let totalActivityTypes = 0; - const entryActivities = {}; - const summaryTypes = {}; + const entryActivities: Record = {}; + const summaryTypes: Record = {}; for (const activity of this.activities) { // Entries are different as multiple updates can be reflected in a single activity if (activity.action === 'update_entry') { diff --git a/src/angular-app/bellows/core/breadcrumbs/breadcrumb.service.ts b/src/angular-app/bellows/core/breadcrumbs/breadcrumb.service.ts index 8f5a3d56d3..c34a74e971 100644 --- a/src/angular-app/bellows/core/breadcrumbs/breadcrumb.service.ts +++ b/src/angular-app/bellows/core/breadcrumbs/breadcrumb.service.ts @@ -15,11 +15,7 @@ export class BreadcrumbService { updateCrumb(id: string, index: number, update: Crumb): void { this.ensureIdIsRegistered(id); const crumb = this.crumbStore[id][index]; - for (const property in update) { - if (update.hasOwnProperty(property)) { - crumb[property] = update[property]; - } - } + Object.assign(crumb, update); } set(id: string, crumbs: Crumb[]): void { diff --git a/src/angular-app/bellows/core/offline/editor-data.service.ts b/src/angular-app/bellows/core/offline/editor-data.service.ts index f194f6781b..c182fb3852 100644 --- a/src/angular-app/bellows/core/offline/editor-data.service.ts +++ b/src/angular-app/bellows/core/offline/editor-data.service.ts @@ -4,7 +4,11 @@ import {SemanticDomainsService} from '../../../languageforge/core/semantic-domai import {LexiconConfigService} from '../../../languageforge/lexicon/core/lexicon-config.service'; import {LexiconUtilityService} from '../../../languageforge/lexicon/core/lexicon-utility.service'; import {LexEntry} from '../../../languageforge/lexicon/shared/model/lex-entry.model'; +import {LexSense} from 'src/angular-app/languageforge/lexicon/shared/model/lex-sense.model'; +import {LexExample} from 'src/angular-app/languageforge/lexicon/shared/model/lex-example.model'; +import {LexMultiText} from 'src/angular-app/languageforge/lexicon/shared/model/lex-multi-text.model'; import {LexMultiValue} from '../../../languageforge/lexicon/shared/model/lex-multi-value.model'; +import {LexOptionListItem} from 'src/angular-app/languageforge/lexicon/shared/model/option-list.model'; import { LexConfigFieldList, LexConfigMultiOptionList, @@ -534,7 +538,7 @@ export class EditorDataService { field = config.entry.fields.senses.fields[fieldKey]; } - angular.forEach(config.entry.fields, (entryField, entryFieldKey:string) => { + angular.forEach(config.entry.fields, (entryField, entryFieldKey:keyof LexEntry) => { if (entryField.type === 'multitext') { angular.forEach(entry[entryFieldKey], (fieldNode, ws:string) => { if (ws && UtilityService.isAudio(ws) && fieldNode.value !== '') { @@ -545,7 +549,7 @@ export class EditorDataService { if (entryFieldKey === 'senses') { angular.forEach(entry.senses, sense => { - angular.forEach(config.entry.fields.senses.fields, (senseField: any, senseFieldKey: string) => { + angular.forEach(config.entry.fields.senses.fields, (senseField: any, senseFieldKey: keyof LexSense) => { if (senseField.type === 'multitext') { angular.forEach(sense[senseFieldKey], (fieldNode: any, ws: string) => { if (ws && UtilityService.isAudio(ws) && fieldNode.value !== '') { @@ -557,7 +561,7 @@ export class EditorDataService { if (senseFieldKey === 'examples') { angular.forEach(sense.examples, example => { angular.forEach(config.entry.fields.senses.fields.examples.fields, - (exampleField: any, exampleFieldKey: string) => { + (exampleField: any, exampleFieldKey: keyof LexExample) => { if (exampleField.type === 'multitext') { angular.forEach(example[exampleFieldKey], (fieldNode: any, ws: string) => { if (ws && UtilityService.isAudio(ws) && fieldNode.value !== '') { @@ -579,25 +583,25 @@ export class EditorDataService { // filter by entry or sense field let dataNode; if (this.entryListModifiers.filterBy.option.level === 'entry') { - dataNode = entry[this.entryListModifiers.filterBy.option.value]; + dataNode = entry[this.entryListModifiers.filterBy.option.value as keyof LexEntry]; } else { // sense level if (entry.senses && entry.senses.length > 0) { - dataNode = entry.senses[0][this.entryListModifiers.filterBy.option.value]; + dataNode = entry.senses[0][this.entryListModifiers.filterBy.option.value as keyof LexSense]; } } if (dataNode) { switch (filterType) { case 'multitext': - if (dataNode[this.entryListModifiers.filterBy.option.inputSystem]) { - containsData = dataNode[this.entryListModifiers.filterBy.option.inputSystem].value !== ''; + if ((dataNode as LexMultiText)[this.entryListModifiers.filterBy.option.inputSystem]) { + containsData = (dataNode as LexMultiText)[this.entryListModifiers.filterBy.option.inputSystem].value !== ''; } break; case 'optionlist': - containsData = dataNode.value !== ''; + containsData = (dataNode as LexOptionListItem).value !== ''; break; case 'multioptionlist': - containsData = (dataNode.values.length > 0); + containsData = ((dataNode as LexMultiValue).values.length > 0); break; } } diff --git a/src/angular-app/bellows/core/session.service.ts b/src/angular-app/bellows/core/session.service.ts index 8840c60688..9d0960bb1b 100644 --- a/src/angular-app/bellows/core/session.service.ts +++ b/src/angular-app/bellows/core/session.service.ts @@ -49,7 +49,7 @@ export class Session { return rights.indexOf(right) !== -1; } - getProjectSetting(setting: string) { + getProjectSetting(setting: keyof ProjectSettings) { return this.data.projectSettings[setting]; } } diff --git a/src/angular-app/bellows/shared/tabset.module.ts b/src/angular-app/bellows/shared/tabset.module.ts index b137e438b9..a65cb55f03 100644 --- a/src/angular-app/bellows/shared/tabset.module.ts +++ b/src/angular-app/bellows/shared/tabset.module.ts @@ -37,7 +37,7 @@ export class TabSetController implements angular.IController { this.tabs[index].onSelect(); this.$scope.active = index; for (const i of Object.keys(this.tabs)) { - this.tabs[i].selected = (parseInt(i, 10) === index); + this.tabs[+i].selected = (+i === index); } } diff --git a/src/angular-app/languageforge/lexicon/editor/comment/lex-comments-view.component.ts b/src/angular-app/languageforge/lexicon/editor/comment/lex-comments-view.component.ts index 21d493296a..8d0a955676 100644 --- a/src/angular-app/languageforge/lexicon/editor/comment/lex-comments-view.component.ts +++ b/src/angular-app/languageforge/lexicon/editor/comment/lex-comments-view.component.ts @@ -74,15 +74,15 @@ export class LexCommentsViewController implements angular.IController { } // get value of multi-text with specified inputSystemTag - if (inputSystemTag != null && model[inputSystemTag] != null) { - return model[inputSystemTag].value; + if (inputSystemTag != null && (model as LexMultiText)[inputSystemTag] != null) { + return (model as LexMultiText)[inputSystemTag].value; } // get first inputSystemTag of a multi-text (no inputSystemTag specified) let fieldValue: string = null; for (const languageTag in model as LexMultiText) { if (fieldValue == null) { - fieldValue = model[languageTag].value; + fieldValue = (model as LexMultiText)[languageTag].value; break; } } diff --git a/src/angular-app/languageforge/lexicon/editor/editor.component.ts b/src/angular-app/languageforge/lexicon/editor/editor.component.ts index 39a12644d6..dc53c313f6 100644 --- a/src/angular-app/languageforge/lexicon/editor/editor.component.ts +++ b/src/angular-app/languageforge/lexicon/editor/editor.component.ts @@ -21,6 +21,8 @@ import { LexiconRightsService, Rights } from '../core/lexicon-rights.service'; import { LexiconSendReceiveService } from '../core/lexicon-send-receive.service'; import { LexiconUtilityService } from '../core/lexicon-utility.service'; import { LexEntry } from '../shared/model/lex-entry.model'; +import { LexSense } from '../shared/model/lex-sense.model'; +import { LexExample } from '../shared/model/lex-example.model'; import { LexPicture } from '../shared/model/lex-picture.model'; import { LexConfig, @@ -867,13 +869,13 @@ export class LexiconEditorController implements angular.IController { if (senseGuid) { for (const a in currentEntry.senses) { if (currentEntry.senses.hasOwnProperty(a) && currentEntry.senses[a].guid === senseGuid) { - senseIndex = a; + senseIndex = +a; if (exampleGuid) { for (const b in currentEntry.senses[a].examples) { if (currentEntry.senses[a].examples.hasOwnProperty(b) && currentEntry.senses[a].examples[b].guid === exampleGuid ) { - exampleIndex = b; + exampleIndex = +b; } } } @@ -885,20 +887,20 @@ export class LexiconEditorController implements angular.IController { const examples = senses.fields.examples as LexConfigFieldList; if (exampleGuid && exampleIndex) { if (currentEntry.senses[senseIndex].examples[exampleIndex].hasOwnProperty(field)) { - currentField = currentEntry.senses[senseIndex].examples[exampleIndex][field]; + currentField = currentEntry.senses[senseIndex].examples[exampleIndex][field as keyof LexExample]; if (examples.fields.hasOwnProperty(field)) { fieldConfig = examples.fields[field]; } } } else if (senseGuid && senseIndex) { if (currentEntry.senses[senseIndex].hasOwnProperty(field)) { - currentField = currentEntry.senses[senseIndex][field]; + currentField = currentEntry.senses[senseIndex][field as keyof LexSense]; if (senses.fields.hasOwnProperty(field)) { fieldConfig = senses.fields[field]; } } } else if (currentEntry.hasOwnProperty(field)) { - currentField = currentEntry[field]; + currentField = currentEntry[field as keyof LexEntry]; if (this.lecConfig.entry.fields.hasOwnProperty(field)) { fieldConfig = this.lecConfig.entry.fields[field]; } @@ -906,8 +908,10 @@ export class LexiconEditorController implements angular.IController { if (currentField !== null) { if (currentField.hasOwnProperty(inputSystem)) { + // @ts-expect-error Typescript should understand .hasOwnProperty, but doesn't currentValue = currentField[inputSystem].value; } else if (currentField.hasOwnProperty('value')) { + // @ts-expect-error Typescript should understand .hasOwnProperty, but doesn't currentValue = currentField.value; } else { currentValue = optionKey; @@ -956,9 +960,9 @@ export class LexiconEditorController implements angular.IController { parts.field = field; parts.fieldConfig = fieldConfig; parts.inputSystem = inputSystem; - parts.sense.index = senseIndex; + parts.sense.index = ""+senseIndex; parts.sense.guid = senseGuid; - parts.example.index = exampleIndex; + parts.example.index = ""+exampleIndex; parts.example.guid = exampleGuid; return parts; } diff --git a/src/angular-app/languageforge/lexicon/editor/field/dc-text.component.ts b/src/angular-app/languageforge/lexicon/editor/field/dc-text.component.ts index 6e700a6cdc..8b233ffedc 100644 --- a/src/angular-app/languageforge/lexicon/editor/field/dc-text.component.ts +++ b/src/angular-app/languageforge/lexicon/editor/field/dc-text.component.ts @@ -50,7 +50,7 @@ export class FieldTextController implements angular.IController { this.fte.toolbar = '[[]]'; } - this.autocapitalize = autocapitalizeHints[this.fteFieldName] || 'none' + this.autocapitalize = autocapitalizeHints[this.fteFieldName as keyof typeof autocapitalizeHints] || 'none' } disabledMsg(): string { diff --git a/src/angular-app/languageforge/lexicon/lexicon-app.component.ts b/src/angular-app/languageforge/lexicon/lexicon-app.component.ts index afdc8a4606..bda50de785 100644 --- a/src/angular-app/languageforge/lexicon/lexicon-app.component.ts +++ b/src/angular-app/languageforge/lexicon/lexicon-app.component.ts @@ -57,7 +57,7 @@ export class LexiconAppController implements angular.IController { if (rights.canEditProject()) { this.lexProjectService.users().then(result => { if (result.ok) { - const users = {}; + const users: Record = {}; for (const user of (result.data.users as User[])) { users[user.id] = user; } diff --git a/src/angular-app/languageforge/lexicon/settings/configuration/field-unified-view.model.ts b/src/angular-app/languageforge/lexicon/settings/configuration/field-unified-view.model.ts index 9b2070ba4f..dcc6654a79 100644 --- a/src/angular-app/languageforge/lexicon/settings/configuration/field-unified-view.model.ts +++ b/src/angular-app/languageforge/lexicon/settings/configuration/field-unified-view.model.ts @@ -136,7 +136,7 @@ export class ConfigurationFieldUnifiedViewModel { } } - static selectAllRoleColumn(settings: SettingsBase[], selectAll: SettingsBase, role: string): void { + static selectAllRoleColumn(settings: SettingsBase[], selectAll: SettingsBase, role: RoleName): void { for (const setting of settings) { if (RequiredFields.requiredFieldList.includes(setting.fieldName)) { setting[role] = true; @@ -158,7 +158,7 @@ export class ConfigurationFieldUnifiedViewModel { } } - static checkIfAllRoleColumnSelected(settings: SettingsBase[], selectAll: SettingsBase, role: string): void { + static checkIfAllRoleColumnSelected(settings: SettingsBase[], selectAll: SettingsBase, role: RoleName): void { selectAll[role] = true; for (const setting of settings) { if (!setting[role]) { @@ -180,7 +180,7 @@ export class ConfigurationFieldUnifiedViewModel { } static checkIfAllRoleSelected(setting: SettingsBase, settings: SettingsBase[], selectAll: SettingsBase, - role: string): void { + role: RoleName): void { ConfigurationFieldUnifiedViewModel.checkIfAllRowSelected(setting); ConfigurationFieldUnifiedViewModel.checkIfAllRoleColumnSelected(settings, selectAll, role); } @@ -405,7 +405,7 @@ export class ConfigurationFieldUnifiedViewModel { return tags; } - private static setInputSystemRoleSettings(tag: string, config: LexiconConfig, role: string, roleType: string, + private static setInputSystemRoleSettings(tag: string, config: LexiconConfig, role: RoleName, roleType: string, inputSystemSettings: InputSystemSettings): void { const roleView: LexRoleViewConfig = config.roleViews[roleType]; if (roleView != null) { @@ -546,13 +546,14 @@ export class FieldSettingsList { selectAllColumns: FieldSettings = new FieldSettings(); } +export type RoleName = 'observer' | 'commenter' | 'contributor' | 'manager'; export class RoleType { observer: string = 'observer'; commenter: string = 'observer_with_comment'; contributor: string = 'contributor'; manager: string = 'project_manager'; - static roles(): string[] { + static roles(): RoleName[] { return ['observer', 'commenter', 'contributor', 'manager']; } } diff --git a/tsconfig.json b/tsconfig.json index 316755fcf5..0ab76cd2f2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,6 @@ "downlevelIteration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "ignoreDeprecations": "5.0", "importHelpers": true, "lib": ["es7", "dom"], "module": "es6", @@ -26,7 +25,6 @@ }, "rootDir": "src/angular-app", "sourceMap": true, - "suppressImplicitAnyIndexErrors": true, "target": "es5", "typeRoots": ["node_modules/@types", "typings"] },