Typescript: Missing `Navigator.clipboard` (clipboard asynchronous API)

Created on 29 Aug 2018  路  20Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.0.0-dev.20180711


Search Terms: navigator, clipboard

Code

console.log(window.navigator.clipboard)

Expected behavior: No error.

Actual behavior:

error TS2339: Property 'clipboard' does not exist on type 'Navigator'

Playground Link: http://www.typescriptlang.org/play/#src=window.navigator.clipboard%3B

Related Issues: none found

W3C: https://www.w3.org/TR/clipboard-apis/#async-clipboard-api
MDN: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard

Working as Intended

Most helpful comment

Hey, isn't it a good moment to go back to this issue and reopen it? I would really love to have it to avoid any workarounds. Chrome supports it from v66 now I have v71. Should be pretty stable.

All 20 comments

Probably missing because it's still a working draft and no browser supports it yet: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard#Browser_compatibility

Why add something to the standard library that is not supported?

no browser supports it yet

It's available in Chrome since 62 (behind a flag) and enabled by default since 66: https://www.chromestatus.com/feature/5861289330999296

Okay, so a single browser supports it already. But it's still an early draft.

We don't add non-standard DOM APIs until they're at least widely adopted.

It is an experimental API. By the way, readText and writeText are also supported in Firefox 63+.

As a workaround:

// navigator.clipboard.d.ts

// Type declarations for Clipboard API
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
interface Clipboard {
  writeText(newClipText: string): Promise<void>;
  // Add any other methods you need here.
}

interface NavigatorClipboard {
  // Only available in a secure context.
  readonly clipboard?: Clipboard;
}

interface Navigator extends NavigatorClipboard {}

It is an experimental API. By the way, readText and writeText are also supported in Firefox 63+.

As a workaround:

// navigator.clipboard.d.ts

// Type declarations for Clipboard API
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
interface Clipboard {
  writeText(newClipText: string): Promise<void>;
  // Add any other methods you need here.
}

interface NavigatorClipboard {
  // Only available in a secure context.
  readonly clipboard?: Clipboard;
}

interface Navigator extends NavigatorClipboard {}

Where should I place this file?

Hey, isn't it a good moment to go back to this issue and reopen it? I would really love to have it to avoid any workarounds. Chrome supports it from v66 now I have v71. Should be pretty stable.

How is "widely adopted" defined? It seems to me that according to http://gs.statcounter.com/ over half of all desktop browser users globally were on a Chrome version that supported this API already for months when the comment "We don't add non-standard DOM APIs until they're at least widely adopted." was made.

@RyanCavanaugh Can you give us any answer?

It is an experimental API. By the way, readText and writeText are also supported in Firefox 63+.
As a workaround:

// navigator.clipboard.d.ts

// Type declarations for Clipboard API
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
interface Clipboard {
  writeText(newClipText: string): Promise<void>;
  // Add any other methods you need here.
}

interface NavigatorClipboard {
  // Only available in a secure context.
  readonly clipboard?: Clipboard;
}

interface Navigator extends NavigatorClipboard {}

Where should I place this file?

I've done that inline like this:

// !! in any place or file !!
// Type declarations for Clipboard API
// https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
interface Clipboard {
  writeText(newClipText: string): Promise<void>;
  // Add any other methods you need here.
}
interface NavigatorClipboard extends Navigator {
  // Only available in a secure context.
  readonly clipboard?: Clipboard;
}
interface NavigatorExtended extends NavigatorClipboard {}

And where you need to use the clipboard you can cast the navigator to the created interface:

    (navigator as NavigatorExtended).clipboard
      .writeText(event.target.innerText)
      .then(() => {
        alert("Copied!");
      }); 

(if the extended interface is in an external file you need to import it first!)

Perhaps not a great solution but if anyone else needs a hacky workaround, this worked for me.

type new var with any

let anyNavigator: any

assign new var to window.navigator

anyNavigator = window.navigator

use new var in place of navigator

anyNavigator.clipboard.writeText(event.target.defaultValue)

seems to work ok with "typescript": "^3.2.4"

So basically, this is fixed since this commit and should be available since 3.4?

Both Chrome and Firefox support the clipboard read and write methods now . Those should be added to the type definitions (which currently only contain readText and writeText).

@fr0 But it's still only a Working Draft.

For me it's a shame that I can't properly play with modern (or experimental) APIs using only standard Typescript definitions, and I have to declare them myself instead.

@1valdis it's very reasonable that Typescript would not include these tools by default. Typescript is targeted to a very wide ranging audience. Giving bleeding-edge tools without warning and by default to developers who are unaware they might be bleeding edge easily leads to unknown bugs. TS is designed to prevent exactly these kinds of issues.

If you're keen to use experimental tools, then you should also be aware of how to extend your definition files to allow them, and how to support users who do not have the latest browsers.

@1valdis it's very reasonable that Typescript would not include these tools by default. Typescript is targeted to a very wide ranging audience. Giving bleeding-edge tools without warning and by default to developers who are unaware they might be bleeding edge easily leads to unknown bugs. TS is designed to prevent exactly these kinds of issues.

If you're keen to use experimental tools, then you should also be aware of how to extend your definition files to allow them, and how to support users who do not have the latest browsers.

Can anyone please share how to do this?

This should be sufficient (it will work using declaration merging). Put it in a clipboard.d.ts file at the top level under on of your type root directories (tsconfig.json -> typeRoots)

interface ClipboardItem {
}

declare var ClipboardItem: {
  prototype: ClipboardItem;
  new(objects: Record<string, Blob>): ClipboardItem;
};

interface Clipboard {
  read?(): Promise<Array<ClipboardItem>>;

  write?(items: Array<ClipboardItem>): Promise<void>;
}

This should be sufficient (it will work using declaration merging). Put it in a clipboard.d.ts file at the top level under on of your type root directories (tsconfig.json -> typeRoots)

interface ClipboardItem {
}

declare var ClipboardItem: {
  prototype: ClipboardItem;
  new(objects: Record<string, Blob>): ClipboardItem;
};

interface Clipboard {
  read?(): Promise<Array<ClipboardItem>>;

  write?(items: Array<ClipboardItem>): Promise<void>;
}

It should be under tsconfig.json -> types, it is a single file (in my case), so no reason to add it into a the rootTypes folders array option.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

manekinekko picture manekinekko  路  3Comments

seanzer picture seanzer  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments