0

I'm working on implementing strict type checking in TypeScript (TS2322). When writing the code like this, the IDE (IntelliJ) correctly validates that these variables are defined as strings:

if (typeof file.key.stringValue !== 'string' ||
    typeof file.publishDate.stringValue !== 'string' ||
    typeof file.size.stringValue !== 'string' ||
    typeof file.url.stringValue !== 'string') {
        throw new Error('missing required values')
}

...but it's not as efficient as it could be... I want to write it like this:

for (const key of ['key', 'publishDate', 'size', 'url']) {
  if (typeof file[key].stringValue !== 'string') {
    throw new Error('missing required values')  
  }
}

but the IDE continues to throw errors. Any suggestions? Sure, I could write some convenience methods to clean this up, but it doesn't seem like I should need to...

Ultimately, I'm constructing a new object:

const clientFile: ClientFile = {
    key: file.key.stringValue,
    publishDate: file.publishDate.stringValue,
    size: parseInt(file.size.stringValue, 0),
    url: file.url.stringValue
}

The error I get from the compiler is: TS2322: Type 'string | undefined' is not assignable to type 'string'. -- indicating the variables COULD be undefined, hence the frustration.

If I use the first sample of type checking, no error is thrown. If I use the second version, the error persists.

I also tried the suggestion already provided. Same result. Errors persist.

const keys: (keyof typeof file)[] = ['key', 'publishDate', 'size', 'url']
for (const key of keys) {
  if (typeof file[key].stringValue !== 'string') {
    throw new Error('missing required values')
  }
}

UPDATE (8/23/2022)

Based on feedback, I've tried a couple more approaches:

function isString(maybeString: unknown): maybeString is string {
  return typeof maybeString === 'string'
}
const keys: (keyof typeof file)[] = ['key', 'publishDate', 'size', 'url']
keys.forEach((key) => {
  if (isString(file[key].stringValue)) {
    throw new Error(`Missing required value in data: ${key}`)
  }
})
const clientFile: ClientFile = {
  key: <string>file.key.stringValue,
  publishDate: <string>file.publishDate.stringValue,
  size: parseInt(<string>file.size.stringValue, 0),
  url: <string>file.url.stringValue
}

This uses the type predicate approach, and does NOT require ignoring an eslint rule, but uses a more cumbersome syntax of prefixing with <string>, whereas this approach doesn't:

const keys: (keyof typeof file)[] = ['key', 'publishDate', 'size', 'url']
keys.forEach((key) => {
  if (typeof file[key].stringValue !== 'string') {
    throw new Error(`Missing required value in data: ${key}`)
  }
})
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const clientFile: ClientFile = {
  key: file.key.stringValue!,
  publishDate: file.publishDate.stringValue!,
  size: parseInt(file.size.stringValue!, 0),
  url: file.url.stringValue!
}
/* eslint-enable @typescript-eslint/no-non-null-assertion */

I'm ultimately going with the second option, as it's fewer keystrokes at the cost of an eslint rule, but open to other opinions.

  • What are the errors that the IDE continues to throw with the second implementation? – Jacob K Aug 22 '22 at 21:37
  • we'll need more code to understand your problem. – Matthieu Riegler Aug 22 '22 at 21:46
  • Are you looking to give `key` a type, maybe? Define `const keys: (keyof typeof file)[] = ['key', 'publishDate', 'size', 'url'];` and use it in the first loop as `for (const key of keys) { }`. – Blackhole Aug 22 '22 at 21:59
  • Updated documentation, provided additional context, tried a suggestion. Thanks all! – Jonathan Lloyd Aug 22 '22 at 23:29
  • A quick solution is to use the non-null assertion operator (see link below), which is a way to tell the compiler: "yeah, you don't know that this value can't be undefined, but _I_ do; trust me". A more robust solution would be to [define your own type guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). – Blackhole Aug 23 '22 at 10:49
  • Does this answer your question? [! operator in typescript after object method](https://stackoverflow.com/questions/38874928/operator-in-typescript-after-object-method) – Blackhole Aug 23 '22 at 10:50
  • Thanks @Blackhole! I'm considering this closed and shared my final comments. Open to your thoughts as well. Appreciate your help and engagement. Cheers! – Jonathan Lloyd Aug 23 '22 at 22:14

0 Answers0