Skip to content
This repository was archived by the owner on Dec 31, 2024. It is now read-only.
This repository was archived by the owner on Dec 31, 2024. It is now read-only.

Any way to use this with TypeScript and not have "as string" all over the codebase? #410

@ffxsam

Description

@ffxsam

This is part question, part feature request.

In my code, I constantly have to typecast:

this.$notify.error({
  title: this.$t('auth.invalidSignupTitle') as string,
  message: this.$t('general.error') as string,
});

If I don't, I get this error: Type 'TranslateResult' is not assignable to type 'string'

Is there some workaround for this? Maybe something we can declare once, so it always returns string?

Activity

Barry-Fisher

Barry-Fisher commented on Oct 17, 2018

@Barry-Fisher

I'm not a maintainer but I've just looked at the index.d.ts file and it appears that the expected return value of the t/$t methods is VueI18n.TranslateResult which in turn is defined as type TranslateResult = string | LocaleMessages;

LocaleMessages is defined as interface LocaleMessages { [key: string]: LocaleMessageObject; } which is an indexable type, which strictly could be empty.

This means that your consuming code will yell at you if a string is expected - e.g. values in objects, calls to Error() etc as a call to t/$t may not be a string.

Digging a bit deeper into the t method call chain (in src/index.ts) it appears that it actually won't always return a string. This exception to a string type return occurs where this._translate is called inside _t into a prepared into the constant ret which can return null, so may that's why the return type is defined as any. Maybe this is an area for exploration and improvement to be stricter on the types defined so that there is always a string (or at least an empty string) to trickle back up the call chain to ensure the return value for t is always a string. In particular, there is a line in _translate which checks !isNull(res). I wonder if this can be refactored to a !== '' check instead.

The thing with typescript is that it enforces best practices with return values and it's best not to mix them wherever possible. For example if a function returns a string for its happy path then the null-ish value ought to be an empty string; not null or false or anything else.

Anyway, just my 2 cents. I don't really have a solution to offer but I hope this information is useful if one of the maintainers are able to investigate this.

darthf1

darthf1 commented on Aug 2, 2019

@darthf1

Is this still on the radar? :)

LbISS

LbISS commented on Sep 4, 2019

@LbISS

Still thousands ' as string'-s in thousands of projects... :)

ffxsam

ffxsam commented on Sep 4, 2019

@ffxsam
Author

Quick note, using .toString() also works, and is probably more correct than type-casting.

LbISS

LbISS commented on Sep 5, 2019

@LbISS

In the end i have used patch-package.

yarn add patch package

Then changed type TranslateResult = string | LocaleMessages; to type TranslateResult = string;
Then
npx patch-package vue-i18n
And to automatically patch typings for all team members added to postinstall in package.json:

"scripts": {
    "postinstall": "patch-package"
}

It'll not work in ALL cases, but it's working for me.

alexeigs

alexeigs commented on Oct 4, 2019

@alexeigs

You could also use $tc instead of $t whenever you just need the translation without further ado as this function returns a string always.

profispojka

profispojka commented on Dec 27, 2019

@profispojka

use this interfaces.d.ts filein root of your projecz

// Extend Vue with our custom types
import Vue from 'vue'
declare module 'vue/types/vue' {
interface Vue {
// == translations
$t: (name: string, attrs?: any) => string
$tc: (name: string, count: number, attrs?: any) => string
}
}

// Needs to be here
export {}

piktur

piktur commented on Jan 22, 2020

@piktur
// vue-i18n.d.ts

import VueI18n, {
  Path, Values, Locale,
} from 'vue-i18n/types'

/**
 * Overloads VueI18n interface to avoid needing to cast return value to string.
 * @see https://github.com/kazupon/vue-i18n/issues/410
 */
declare module 'vue-i18n/types' {
  export default class VueI18n {
    t(key: Path, locale: Locale, values?: Values): string;
    t(key: Path, values?: Values): string;
  }
}

declare module 'vue/types/vue' {
  interface Vue {
    $t: typeof VueI18n.prototype.t;
  }

  interface VueConstructor<V extends Vue = Vue> {
    i18n: typeof VueI18n.prototype;
  }
}

export {}

Did the trick for me.

19 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @kazupon@Glandos@LbISS@Barry-Fisher@piktur

        Issue actions

          Any way to use this with TypeScript and not have "as string" all over the codebase? · Issue #410 · kazupon/vue-i18n