Leo Messi
Leo Messi

Reputation: 6186

React Typescript types for monaco-editor

Having the following code snippet that works fine with React + Javascript:

import React, { useRef } from "react";

import Editor from "@monaco-editor/react";

function App() {
  const editorRef = useRef(null);

  function handleEditorDidMount(editor, monaco) {
    editorRef.current = editor;
  }

  function showValue() {
    alert(editorRef.current?.getValue());
  }

  return (
    <>
      <button onClick={showValue}>Show value</button>
      <Editor
        height="90vh"
        defaultLanguage="javascript"
        defaultValue="// some comment"
        onMount={handleEditorDidMount}
      />
    </>
  );
}

export default App;

Sandbox here.

I need to use it in a React + Typescript app so I have to add types.

What type should be used for editor?

Tried like this:

  function handleEditorDidMount(editor: HTMLInputElement) {
    editorRef?.current = editor;
  }

  function showValue() {
    // eslint-disable-next-line no-alert
    alert(editorRef?.current?.getValue());
  }

For the first method, the error is:

The left-hand side of an assignment expression may not be an optional property access.ts(2779)
const editorRef: React.MutableRefObject<null>

For the second:

Property 'getValue' does not exist on type 'never'.ts(2339)

Any suggestions?

Upvotes: 5

Views: 3985

Answers (4)

Steve Chow
Steve Chow

Reputation: 11

To solve the TypeScript issues you're encountering, you can destructure the OnMount type from the Monaco editor package. The OnMount type is the type of the onMount prop, and you can extract the type for the editor by accessing the first parameter of the OnMount type.

Here's how you can apply this solution:

import { Editor as MonacoEditor, type OnMount } from "@monaco-editor/react";

// Extract the type of the editor from the OnMount prop
type IStandaloneCodeEditor = Parameters<OnMount>[0];

...

const editorRef = useRef<IStandaloneCodeEditor | null>(null);

const handleEditorDidMount = (editor: IStandaloneCodeEditor) => {
    editorRef.current = editor;
};
  1. OnMount type: This type represents the function signature for the onMount callback. By using Parameters<OnMount>[0], we extract the first parameter of the onMount function, which is the editor instance, and assign it to the IStandaloneCodeEditor type.
  2. useRef<IStandaloneCodeEditor | null>(null): This ensures that the editorRef is typed correctly to hold a Monaco editor instance or null initially.
  3. handleEditorDidMount function: This function is typed to accept an editor instance of type IStandaloneCodeEditor.

Upvotes: 1

namti
namti

Reputation: 71

According to the official documentation, the monaco react library is using monaco-editor as its peer dependency.

NOTE: For TypeScript type definitions, this package uses the monaco-editor package as a peer dependency. So, if you need types and don't already have the monaco-editor package installed, you will need to do so

In my case, I installed monaco-editor as my dev dependency since I just need its type definitions. As @yilmaz specified, we can use the type editor.IStandaloneCodeEditor for the ref.

import { editor } from 'monaco-editor';
...

const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);

Upvotes: 0

Yilmaz
Yilmaz

Reputation: 49671

  • import type onMount

    import MonacoEditor, { OnMount } from "@monaco-editor/react";
    

if you hover on onMount:

  type OnMount = (editor: monaco.editor.IStandaloneCodeEditor, monaco: Monaco) => void
  • use it on handleDidMount:

    const handleEditorDidMount:OnMount=(editor) { editorRef?.current = editor; }

if you see the type,handleEditorDidMount takes 2 args

const handleEditorDidMount:OnMount=(editor,_monaco) {
    editorRef?.current = editor;
  }

Since you are using OnMount type, args type will be inferred by typescript:

          editor: editor.IStandaloneCodeEditor

Upvotes: 7

Casper Kuethe
Casper Kuethe

Reputation: 1130

The returned type of useRef(null) is React.MutableRefObject<null>. But you want typescript to know you're gonna pass an input element to the ref, so you have to explicitily set its type const editorRef = useRef(null) as React.MutableRefObject<null | HTMLInputElement>;

editorRef.current will always be defined, but the type of editorRef.current is now null | HTMLInputElement, because the type of current is the type you pass into the generic of React.MutableRefObject.

Regarding this error.

The left-hand side of an assignment expression may not be an optional property access.ts(2779)
const editorRef: React.MutableRefObject<null>

editorRef.current will always be defined. The value however can be null as you have explicitily typed. So no need for the ?

Knowing this you can adjust your last part of code to

function showValue() {
    // eslint-disable-next-line no-alert
    alert(editorRef.current?.getValue());
}

Upvotes: 0

Related Questions