2

What I want is to extend the String prototype to add a .trimSlashes() method to wipe slashes from either end of a string; I can't make it do in-place replacement (instead of requiring to return a string, just change the own string on call), but that'd be another issue.

I am using TypeScript version 3.8.3.

So I have this trimSlashes.ts file:

import * as fs from "fs";

interface String {
  trimSlashes(this: string) : string;
}

String.prototype.trimSlashes = function (this : string) : string {
  var str = this;
  if (str.startsWith("/")) {
    str = str.replace(/^\/+/, "")
  }
  if (str.endsWith("/")) {
    str = str.replace(/\/+$/, "");
  }

  return str;
}

let test = "//myTest/";

console.log("Original string: " + test);
test.trimSlashes();

console.log("Trimmed slashes: " + test);

console.log("File or directory exists: " + fs.existsSync(test));

I added the fs context as it was required to trigger the error where the compiler stops the parse complaining that Property 'trimSlashes' does not exist on type 'String'.. Without the fs code, it builds and run over NodeJS.

Additional notes

There are several questions like this but seems none asks it for version 3.8 and all answers I could find did not apply.

I tried creating a separate .d.ts file, including it in source, and now I'm trying what I believe to be the simplest: declaring all in one file. I wouldn't mind having a .d.ts file if required, but I just can't get it to work.

0

1 Answer 1

2

I believe that adding import * as fs from 'fs' forces the compiler to treat that file as a module. When that happens, Typescript becomes aware there is a global scope in a greater program that may be affected by this file, and won't let mess with global prototypes unless you tell it you really mean to.

To explicitly modify a global interface, use declare global.

declare global {
  interface String {
    trimSlashes(this: string): string;
  }
}

Playground

I would put that in a string.d.ts in the root of my project. Typescript should pick that up and allow the method. Just be sure to import the file that adds this function to the actual prototype before any code that might use it or you will still get runtime errors.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the suggestion. unfortunately just creating a string.d.ts and adding the declare global block won't do. Only way I can use it is by copypasting the whole block in the file. Any idea how can I force it to find string.d.ts, which lies in the same folder the trimSlashes.ts file is? (side note: your answer nailed the issue; it is just your suggestion -- which I fully agree and would love to be able to employ -- doesn't seem to add up)
the thing is probably not found because I use noImplicitAny: true and I would kind of like to control what gets in or not, even if I needed to explicitly include the .d.ts file... if that makes sense...
Okay, I figured it out. In short: (a) no declare global in string.d.ts, (b) a utils.ts defining the trimSlashes() extension, (c) my "client code" importing with import * as util from "./utils";.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.